genlib can return 4 arguments
[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 "string.hxx"
31 #include "parser.hxx"
32 #include "context.hxx"
33 #include "io_gw.hxx"
34 #include "scilabWrite.hxx"
35 #include "expandPathVariable.h"
36 #include "configvariable.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(typed_list &in, int _iRetCount, typed_list &out)
70 {
71     int succes = 1;
72     std::vector<std::wstring> failed_files;
73     std::vector<std::wstring> success_files;
74     std::vector<std::wstring> funcs;
75
76     wchar_t pstParseFile[PATH_MAX + FILENAME_MAX];
77     wchar_t pstVerbose[65535];
78
79     int iNbFile             = 0;
80     wchar_t *pstParsePath      = NULL;
81     int iParsePathLen           = 0;
82     wchar_t* pstLibName         = NULL;
83     bool bVerbose           = false;
84
85     if (in.size() < 1 || in.size() > 4)
86     {
87         Scierror(78, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "genlib", 1, 4);
88         return Function::Error;
89     }
90
91     //param 1, library name
92     InternalType* pIT = in[0];
93     if (pIT->isString() == false)
94     {
95         Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "genlib", 1);
96         return Function::Error;
97     }
98
99     String *pS = pIT->getAs<String>();
100     if (pS->getSize() != 1)
101     {
102         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "genlib", 1);
103         return Function::Error;
104     }
105     pstLibName = pS->get(0);
106
107     //param 2, library path
108     if (in.size() > 1)
109     {
110         pIT = in[1];
111         if (pIT->isString() == false)
112         {
113             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "genlib", 2);
114             return Function::Error;
115         }
116     }
117     else
118     {
119         int ierr = 0;
120         pIT = new String(scigetcwd(&ierr));
121     }
122
123     pS = pIT->getAs<String>();
124     if (pS->isScalar() == false)
125     {
126         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "genlib", 2);
127         return Function::Error;
128     }
129
130     if (in.size() > 2)
131     {
132         //force flag, do nothing but keep for compatibility
133     }
134
135     if (in.size() > 3)
136     {
137         //verbose flag
138         pIT = in[3];
139         if (pIT->isBool() == false)
140         {
141             return Function::Error;
142         }
143
144         bVerbose = pIT->getAs<Bool>()->get()[0] == 1;
145     }
146
147     wchar_t* pstFile = pS->get(0);
148     pstParsePath = expandPathVariableW(pstFile);
149
150     os_swprintf(pstParseFile, PATH_MAX + FILENAME_MAX, L"%ls%lslib", pstParsePath, FILE_SEPARATOR);
151
152     if (bVerbose)
153     {
154         os_swprintf(pstVerbose, 65535, _W("-- Creation of [%ls] (Macros) --\n").c_str(), pstLibName);
155
156         //save current prompt mode
157         int oldVal = ConfigVariable::getPromptMode();
158         //set mode silent for errors
159         ConfigVariable::setPromptMode(0);
160         scilabWriteW(pstVerbose);
161         //restore previous prompt mode
162         ConfigVariable::setPromptMode(oldVal);
163     }
164
165     MacroInfoList lstOld;
166     if (FileExistW(pstParseFile))
167     {
168         //read it to get previous information like md5
169         std::wstring libname;
170         parseLibFile(pstParseFile, lstOld, libname);
171         deleteafileW(pstParseFile);
172     }
173
174     xmlTextWriterPtr pWriter = openXMLFile(pstParseFile, pstLibName);
175
176     if (pWriter == NULL)
177     {
178         os_swprintf(pstVerbose, 65535, _W("%ls: Cannot open file ''%ls''.\n").c_str(), L"genlib", pstParseFile);
179         scilabWriteW(pstVerbose);
180
181         out.push_back(new Bool(0));
182         FREE(pstParsePath);
183         return Function::OK;
184     }
185
186
187     wchar_t **pstPath = findfilesW(pstParsePath, L"*.sci", &iNbFile, FALSE);
188
189     if (pstPath)
190     {
191         Library* pLib = new Library(pstParsePath);
192         for (int k = 0 ; k < iNbFile ; k++)
193         {
194             //version with direct parsing
195             //parse the file to find all functions
196             wstring stFullPath = wstring(pstParsePath) + wstring(FILE_SEPARATOR) + wstring(pstPath[k]);
197             wstring stFullPathBin(stFullPath);
198             stFullPathBin.replace(stFullPathBin.end() - 3, stFullPathBin.end(), L"bin");
199             wstring pstPathBin(pstPath[k]);
200             pstPathBin.replace(pstPathBin.end() - 3, pstPathBin.end(), L"bin");
201
202             //compute file md5
203             FILE* fmdf5 = os_wfopen(stFullPath.data(), L"rb");
204             char* md5 = md5_file(fmdf5);
205             fclose(fmdf5);
206
207             wchar_t* wmd5 = to_wide_string(md5);
208             FREE(md5);
209             std::wstring wide_md5(wmd5);
210             FREE(wmd5);
211
212             //check if is exist in old file
213
214             MacroInfoList::iterator it = lstOld.find(pstPathBin);
215             if (it != lstOld.end())
216             {
217                 if (wide_md5 == (*it).second.md5)
218                 {
219                     //file not change, we can skip it
220                     AddMacroToXML(pWriter, (*it).second.name, pstPathBin, wide_md5);
221                     pLib->add((*it).second.name, new MacroFile((*it).second.name, stFullPathBin, pstLibName));
222                     success_files.push_back(stFullPath);
223                     funcs.push_back((*it).second.name);
224                     continue;
225                 }
226             }
227
228             if (bVerbose)
229             {
230                 sciprint(_("%ls: Processing file: %ls\n"), L"genlib", pstPath[k]);
231             }
232
233             Parser parser;
234             parser.parseFile(stFullPath, ConfigVariable::getSCIPath());
235             if (parser.getExitStatus() !=  Parser::Succeded)
236             {
237                 scilabWriteW(parser.getErrorMessage());
238                 sciprint(_("%ls: Error in file %ls.\n"), L"genlib", stFullPath.data());
239                 failed_files.push_back(stFullPath);
240                 succes = 0;
241                 continue;
242             }
243
244             //serialize ast
245             ast::SerializeVisitor* s = new ast::SerializeVisitor(parser.getTree());
246
247             unsigned char* serialAst = s->serialize();
248             // Header is : buffer size (4 bytes) + scilab version (4 bytes)
249             unsigned int size = *((unsigned int*)serialAst);
250
251             FILE* f = os_wfopen(stFullPathBin.c_str(), L"wb");
252             fwrite(serialAst, 1, size, f);
253             fclose(f);
254
255             ast::exps_t LExp = parser.getTree()->getAs<ast::SeqExp>()->getExps();
256             for (ast::exps_t::iterator j = LExp.begin(), itEnd = LExp.end() ; j != itEnd ; ++j)
257             {
258                 if ((*j)->isFunctionDec())
259                 {
260                     ast::FunctionDec* pFD = (*j)->getAs<ast::FunctionDec>();
261                     const wstring& name = pFD->getSymbol().getName();
262                     if (name + L".sci" == pstPath[k])
263                     {
264                         if (AddMacroToXML(pWriter, name, pstPathBin, wide_md5) == false)
265                         {
266                             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]);
267                             scilabWriteW(pstVerbose);
268                         }
269
270                         pLib->add(name, new MacroFile(name, stFullPathBin, pstLibName));
271                         success_files.push_back(stFullPath);
272                         funcs.push_back(name);
273                         break;
274                     }
275                 }
276             }
277
278             delete s;
279             free(serialAst);
280             delete parser.getTree();
281         }
282
283         symbol::Context* ctx = symbol::Context::getInstance();
284         symbol::Symbol sym = symbol::Symbol(pstLibName);
285         if (ctx->isprotected(sym) == false)
286         {
287             ctx->put(symbol::Symbol(pstLibName), pLib);
288         }
289         else
290         {
291             Scierror(999, _("Redefining permanent variable.\n"));
292             return Function::Error;
293         }
294     }
295
296     freeArrayOfWideString(pstPath, iNbFile);
297
298     out.push_back(new Bool(succes));
299
300     if (_iRetCount > 1)
301     {
302         int size = static_cast<int>(funcs.size());
303         if (size == 0)
304         {
305             out.push_back(Double::Empty());
306         }
307         else
308         {
309             String* s = new String(size, 1);
310
311             for (int i = 0; i < size; ++i)
312             {
313                 s->set(i, funcs[i].data());
314             }
315
316             out.push_back(s);
317         }
318     }
319
320     if (_iRetCount > 2)
321     {
322         int size = static_cast<int>(success_files.size());
323         if (size == 0)
324         {
325             out.push_back(Double::Empty());
326         }
327         else
328         {
329             String* s = new String(size, 1);
330
331             for (int i = 0; i < size; ++i)
332             {
333                 s->set(i, success_files[i].data());
334             }
335
336             out.push_back(s);
337         }
338     }
339
340     if (_iRetCount > 3)
341     {
342         int size = static_cast<int>(failed_files.size());
343         if (size == 0)
344         {
345             out.push_back(Double::Empty());
346         }
347         else
348         {
349             String* s = new String(size, 1);
350
351             for (int i = 0; i < size; ++i)
352             {
353                 s->set(i, failed_files[i].data());
354             }
355
356             out.push_back(s);
357         }
358     }
359
360     FREE(pstParsePath);
361     closeXMLFile(pWriter);
362     return Function::OK;
363 }
364
365 void closeXMLFile(xmlTextWriterPtr _pWriter)
366 {
367     int iLen;
368
369     //close opened nodes
370     iLen = xmlTextWriterEndElement(_pWriter);
371     if (iLen < 0)
372     {
373         return;
374     }
375
376     //close document
377     iLen = xmlTextWriterEndDocument(_pWriter);
378     if (iLen < 0)
379     {
380         return;
381     }
382
383     //close xml writer
384     xmlFreeTextWriter(_pWriter);
385 }
386
387 xmlTextWriterPtr openXMLFile(const wchar_t *_pstFilename, const wchar_t* _pstLibName)
388 {
389     int iLen;
390     xmlTextWriterPtr pWriter = NULL;;
391     char *pstFilename = wide_string_to_UTF8(_pstFilename);
392     char *pstLibName = wide_string_to_UTF8(_pstLibName);
393
394
395     //create a writer
396     pWriter = xmlNewTextWriterFilename(pstFilename, 0);
397     if (pWriter == NULL)
398     {
399         return NULL;
400     }
401
402     //setup indentation
403     xmlTextWriterSetIndent (pWriter, 1);
404     xmlTextWriterSetIndentString (pWriter, (xmlChar*)"  ");
405
406     //create a new document
407     iLen = xmlTextWriterStartDocument(pWriter, NULL, DEFAULT_ENCODING, "no");
408     if (iLen < 0)
409     {
410         return NULL;
411     }
412
413     //add a node "scilablib"
414     iLen = xmlTextWriterStartElement(pWriter, (xmlChar*)"scilablib");
415     if (iLen < 0)
416     {
417         return NULL;
418     }
419
420     //Add attribute "name"
421     iLen = xmlTextWriterWriteAttribute(pWriter, (xmlChar*)"name", (xmlChar*)pstLibName);
422     if (iLen < 0)
423     {
424         return NULL;
425     }
426
427     FREE(pstFilename);
428     FREE(pstLibName);
429
430     return pWriter;
431 }
432
433 bool AddMacroToXML(xmlTextWriterPtr _pWriter, const wstring& name, const wstring& file, const wstring& md5)
434 {
435     int iLen;
436
437     if (_pWriter == NULL)
438     {
439         return false;
440     }
441
442     //create node "macro"
443     iLen = xmlTextWriterStartElement(_pWriter, (xmlChar*)"macro");
444     if (iLen < 0)
445     {
446         return false;
447     }
448
449     //Add attribute "name"
450     char* pst1 = wide_string_to_UTF8(name.data());
451     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"name", (xmlChar*)pst1);
452     if (iLen < 0)
453     {
454         return false;
455     }
456     FREE(pst1);
457
458     //Add attribute "file"
459     char* pst2 = wide_string_to_UTF8(file.data());
460     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"file", (xmlChar*)pst2);
461     if (iLen < 0)
462     {
463         return false;
464     }
465     FREE(pst2);
466
467     //Add attribute "md5"
468     char* pst3 = wide_string_to_UTF8(md5.data());
469     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"md5", (xmlChar*)pst3);
470     if (iLen < 0)
471     {
472         return false;
473     }
474     FREE(pst3);
475
476     //close "macro" node
477     iLen = xmlTextWriterEndElement(_pWriter);
478     if (iLen < 0)
479     {
480         return false;
481     }
482
483     return true;
484 }