639611caa1f119b489a05a91d26f6cfa8cae81b9
[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
41 extern "C"
42 {
43 #include "setenvvar.h"
44 #include "sci_malloc.h"
45 #include "localization.h"
46 #include "PATH_MAX.h"
47 #include "findfiles.h"
48 #include "FileExist.h"
49 #include "deleteafile.h"
50 #include "os_string.h"
51 #include "splitpath.h"
52 #include "os_wfopen.h"
53 #include "sciprint.h"
54 #include "freeArrayOfString.h"
55 #include "Scierror.h"
56 #include "scicurdir.h"
57
58 }
59
60
61 xmlTextWriterPtr openXMLFile(const wchar_t *_pstFilename, const wchar_t* _pstLibName);
62 void closeXMLFile(xmlTextWriterPtr _pWriter);
63 bool AddMacroToXML(xmlTextWriterPtr _pWriter, pair<wstring, wstring> _pair);
64
65
66 using namespace types;
67 /*--------------------------------------------------------------------------*/
68 Function::ReturnValue sci_genlib(types::typed_list &in, int _iRetCount, types::typed_list &out)
69 {
70     wchar_t pstParseFile[PATH_MAX + FILENAME_MAX];
71     wchar_t pstVerbose[65535];
72
73     int iNbFile             = 0;
74     wchar_t *pstParsePath      = NULL;
75     int iParsePathLen           = 0;
76     wchar_t* pstLibName         = NULL;
77     bool bVerbose           = false;
78
79     if (in.size() < 1 || in.size() > 4)
80     {
81         Scierror(78, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "genlib", 1, 4);
82         return Function::Error;
83     }
84
85     //param 1, library name
86     InternalType* pIT = in[0];
87     if (pIT->isString() == false)
88     {
89         Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "genlib", 1);
90         return Function::Error;
91     }
92
93     String *pS = pIT->getAs<types::String>();
94     if (pS->getSize() != 1)
95     {
96         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "genlib", 1);
97         return Function::Error;
98     }
99     pstLibName = pS->get(0);
100
101     //param 2, library path
102     if (in.size() > 1)
103     {
104         pIT = in[1];
105         if (pIT->isString() == false)
106         {
107             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "genlib", 2);
108             return Function::Error;
109         }
110     }
111     else
112     {
113         int ierr = 0;
114         pIT = new types::String(scigetcwd(&ierr));
115     }
116
117     pS = pIT->getAs<types::String>();
118     if (pS->isScalar() == false)
119     {
120         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "genlib", 2);
121         return Function::Error;
122     }
123
124     if (in.size() > 2)
125     {
126         //force flag, do nothing but keep for compatibility
127     }
128
129     if (in.size() > 3)
130     {
131         //verbose flag
132         pIT = in[3];
133         if (pIT->isBool() == false)
134         {
135             return Function::Error;
136         }
137
138         bVerbose = pIT->getAs<types::Bool>()->get()[0] == 1;
139     }
140
141     wchar_t* pstFile = pS->get(0);
142     pstParsePath = expandPathVariableW(pstFile);
143
144     os_swprintf(pstParseFile, PATH_MAX + FILENAME_MAX, L"%ls%lslib", pstParsePath, FILE_SEPARATOR);
145
146     if (bVerbose)
147     {
148         os_swprintf(pstVerbose, 65535, _W("-- Creation of [%ls] (Macros) --\n").c_str(), pstLibName);
149
150         //save current prompt mode
151         int oldVal = ConfigVariable::getPromptMode();
152         //set mode silent for errors
153         ConfigVariable::setPromptMode(0);
154         scilabWriteW(pstVerbose);
155         //restore previous prompt mode
156         ConfigVariable::setPromptMode(oldVal);
157     }
158
159     if (FileExistW(pstParseFile))
160     {
161         deleteafileW(pstParseFile);
162     }
163
164     xmlTextWriterPtr pWriter = openXMLFile(pstParseFile, pstLibName);
165
166     if (pWriter == NULL)
167     {
168         os_swprintf(pstVerbose, 65535, _W("%ls: Cannot open file ''%ls''.\n").c_str(), L"genlib", pstParseFile);
169         scilabWriteW(pstVerbose);
170
171         out.push_back(new Bool(0));
172         FREE(pstParsePath);
173         return Function::OK;
174     }
175
176
177     wchar_t **pstPath = findfilesW(pstParsePath, L"*.sci", &iNbFile, FALSE);
178
179     if (pstPath)
180     {
181         types::Library* pLib = new types::Library(pstParsePath);
182         for (int k = 0 ; k < iNbFile ; k++)
183         {
184             //version with direct parsing
185             //parse the file to find all functions
186             wstring stFullPath = wstring(pstParsePath) + wstring(FILE_SEPARATOR) + wstring(pstPath[k]);
187             wstring stFullPathBin(stFullPath);
188             stFullPathBin.replace(stFullPathBin.end() - 3, stFullPathBin.end(), L"bin");
189             wstring pstPathBin(pstPath[k]);
190             pstPathBin.replace(pstPathBin.end() - 3, pstPathBin.end(), L"bin");
191
192             if (bVerbose)
193             {
194                 sciprint(_("%ls: Processing file: %ls\n"), L"genlib", pstPath[k]);
195             }
196
197             Parser parser;
198             parser.parseFile(stFullPath, ConfigVariable::getSCIPath());
199             if (parser.getExitStatus() !=  Parser::Succeded)
200             {
201                 scilabWriteW(parser.getErrorMessage());
202                 Scierror(999, _("%ls: Error in file %ls.\n"), L"genlib", stFullPath.data());
203                 return Function::Error;
204             }
205
206             //serialize ast
207             ast::SerializeVisitor* s = new ast::SerializeVisitor(parser.getTree());
208
209             unsigned char* serialAst = s->serialize();
210             // Header is : buffer size (4 bytes) + scilab version (4 bytes)
211             unsigned int size = *((unsigned int*)serialAst);
212
213             FILE* f = os_wfopen(stFullPathBin.c_str(), L"wb");
214             fwrite(serialAst, 1, size, f);
215             fclose(f);
216
217             ast::exps_t LExp = parser.getTree()->getAs<ast::SeqExp>()->getExps();
218             for (ast::exps_t::iterator j = LExp.begin(), itEnd = LExp.end() ; j != itEnd ; ++j)
219             {
220                 if ((*j)->isFunctionDec())
221                 {
222                     ast::FunctionDec* pFD = (*j)->getAs<ast::FunctionDec>();
223                     const wstring& name = pFD->getSymbol().getName();
224                     if (name + L".sci" == pstPath[k])
225                     {
226                         if (AddMacroToXML(pWriter, pair<wstring, wstring>(name, pstPathBin)) == false)
227                         {
228                             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]);
229                             scilabWriteW(pstVerbose);
230                         }
231
232                         pLib->add(name, new types::MacroFile(name, stFullPathBin, pstLibName));
233                         break;
234                     }
235                 }
236             }
237
238             delete s;
239             free(serialAst);
240             delete parser.getTree();
241         }
242
243         symbol::Context* ctx = symbol::Context::getInstance();
244         symbol::Symbol sym = symbol::Symbol(pstLibName);
245         if (ctx->isprotected(sym) == false)
246         {
247             ctx->put(symbol::Symbol(pstLibName), pLib);
248         }
249         else
250         {
251             Scierror(999, _("Redefining permanent variable.\n"));
252             return Function::Error;
253         }
254     }
255
256     freeArrayOfWideString(pstPath, iNbFile);
257     out.push_back(new Bool(1));
258     FREE(pstParsePath);
259     closeXMLFile(pWriter);
260     return Function::OK;
261 }
262
263 void closeXMLFile(xmlTextWriterPtr _pWriter)
264 {
265     int iLen;
266
267     //close opened nodes
268     iLen = xmlTextWriterEndElement(_pWriter);
269     if (iLen < 0)
270     {
271         return;
272     }
273
274     //close document
275     iLen = xmlTextWriterEndDocument(_pWriter);
276     if (iLen < 0)
277     {
278         return;
279     }
280
281     //close xml writer
282     xmlFreeTextWriter(_pWriter);
283 }
284
285 xmlTextWriterPtr openXMLFile(const wchar_t *_pstFilename, const wchar_t* _pstLibName)
286 {
287     int iLen;
288     xmlTextWriterPtr pWriter = NULL;;
289     char *pstFilename = wide_string_to_UTF8(_pstFilename);
290     char *pstLibName = wide_string_to_UTF8(_pstLibName);
291
292
293     //create a writer
294     pWriter = xmlNewTextWriterFilename(pstFilename, 0);
295     if (pWriter == NULL)
296     {
297         return NULL;
298     }
299
300     //setup indentation
301     xmlTextWriterSetIndent (pWriter, 1);
302     xmlTextWriterSetIndentString (pWriter, (xmlChar*)"  ");
303
304     //create a new document
305     iLen = xmlTextWriterStartDocument(pWriter, NULL, DEFAULT_ENCODING, "no");
306     if (iLen < 0)
307     {
308         return NULL;
309     }
310
311     //add a node "scilablib"
312     iLen = xmlTextWriterStartElement(pWriter, (xmlChar*)"scilablib");
313     if (iLen < 0)
314     {
315         return NULL;
316     }
317
318     //Add attribute "name"
319     iLen = xmlTextWriterWriteAttribute(pWriter, (xmlChar*)"name", (xmlChar*)pstLibName);
320     if (iLen < 0)
321     {
322         return NULL;
323     }
324
325     FREE(pstFilename);
326     FREE(pstLibName);
327
328     return pWriter;
329 }
330
331 bool AddMacroToXML(xmlTextWriterPtr _pWriter, pair<wstring, wstring> _pair)
332 {
333     int iLen;
334
335     if (_pWriter == NULL)
336     {
337         return false;
338     }
339
340     //create node "macro"
341     iLen = xmlTextWriterStartElement(_pWriter, (xmlChar*)"macro");
342     if (iLen < 0)
343     {
344         return false;
345     }
346
347     //Add attribute "name"
348     char* pstFirst = wide_string_to_UTF8(_pair.first.c_str());
349     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"name", (xmlChar*)pstFirst);
350     if (iLen < 0)
351     {
352         return false;
353     }
354     FREE(pstFirst);
355
356     //Add attribute "file"
357     char* pstSecond = wide_string_to_UTF8(_pair.second.c_str());
358     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"file", (xmlChar*)pstSecond);
359     if (iLen < 0)
360     {
361         return false;
362     }
363     FREE(pstSecond);
364
365     //close "macro" node
366     iLen = xmlTextWriterEndElement(_pWriter);
367     if (iLen < 0)
368     {
369         return false;
370     }
371     return true;
372 }