]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
Some comments updated
[bbtk.git] / kernel / src / bbtkInterpreter.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkInterpreter.cxx,v $ $
5   Language:  C++
6   Date:      $Date: 2008/07/03 13:59:32 $
7   Version:   $Revision: 1.68 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/bbtk/License.html for details.
12
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18 /**
19  *  \file 
20  *  \brief class Interpreter :
21  */
22
23 #include "bbtkInterpreter.h"
24 #include "bbtkExecuter.h"
25 #include "bbtkTranscriptor.h"
26 #include "bbtkMessageManager.h"
27 #include "bbtkConfigurationFile.h"
28 #include "bbtkUtilities.h"
29 #include "bbtkWxBlackBox.h"
30 #include <sys/stat.h>
31 #include <algorithm>
32 #ifdef CMAKE_HAVE_TERMIOS_H
33 #include <termios.h>
34 #define BBTK_USE_TERMIOS_BASED_PROMPT
35 #endif
36
37 #include <string>
38
39 namespace bbtk
40 {
41
42  //=======================================================================
43   Interpreter::Pointer Interpreter::New(const std::string& cpp_file) 
44   {
45     bbtkDebugMessage("Kernel",9,"Interpreter::New('"<<cpp_file<<"')"<<std::endl);
46     return MakePointer(new Interpreter(cpp_file));
47   }
48  //=======================================================================
49
50  //=======================================================================
51   Interpreter::Pointer Interpreter::New(VirtualExec::Pointer e) 
52   {
53     bbtkDebugMessage("Kernel",9,"Interpreter::New(VirtualExec)"<<std::endl);
54     return MakePointer(new Interpreter(e));
55   }
56  //=======================================================================
57
58  //=======================================================================
59   Interpreter::Interpreter(const std::string& cpp_file) 
60   {
61     Init(VirtualExec::Pointer(), cpp_file);
62   }
63   //=======================================================================
64
65  //=======================================================================
66   Interpreter::Interpreter(VirtualExec::Pointer e) 
67   {
68     Init(e,"");
69   }
70   //=======================================================================
71
72   //=======================================================================
73   void Interpreter::Init(VirtualExec::Pointer e, const std::string& cpp_file) 
74   {
75     mUser = 0;
76     mCommandLine = false;
77     mThrow = false;
78     bufferNb =0;  
79     bbtk::MessageManager::RegisterMessageType("echo","Level>0 : Prints the output of the 'print' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
80     bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
81     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
82     if (e)
83       {
84         mVirtualExecuter = e;
85       }
86     else if (cpp_file.size()!=0)
87       {
88         mVirtualExecuter = boost::static_pointer_cast<VirtualExec>(bbtk::Transcriptor::New(cpp_file));
89       }
90     else 
91       {
92         bbtk::Executer::Pointer exe = bbtk::Executer::New();
93         mRealExecuter = exe;
94         mVirtualExecuter = boost::static_pointer_cast<VirtualExec>(exe);
95       }
96
97     // Lock this pointer or will auto-destruct !!
98     if (!e) mVirtualExecuter->SetInterpreter(MakePointer(this,true));
99     
100     // For the time being, comment out previous line, and
101     // uncomment next line to check Transcriptor
102
103     //mVirtualExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
104
105     // Builds the commands dict
106     CommandInfoType info;
107    
108     info.keyword = "new";
109     info.argmin = 2;
110     info.argmax = 2;
111     info.code = cNew;
112     info.syntax = "new <type> <name>";
113     info.help = "Creates a new black box of type <type> with name <name>";
114     mCommandDict[info.keyword] = info;
115     
116     info.keyword = "delete";
117     info.argmin = 1;
118     info.argmax = 1;
119     info.code = cDelete;
120     info.syntax = "delete <box>";
121     info.help = "Deletes the black box of name <box>";
122     mCommandDict[info.keyword] = info;
123
124     info.keyword = "newgui";
125     info.argmin = 2;
126     info.argmax = 2;
127     info.code = cNewGUI;
128     info.syntax = "newgui <box> <name>";
129     info.help = "Automatically creates a graphical user interface with name <name> for the black box <box> and connects it to the box inputs";
130     mCommandDict[info.keyword] = info;
131
132     info.keyword = "connect";
133     info.argmin = 2;
134     info.argmax = 2;
135     info.code = cConnect;
136     info.syntax = "connect <box1.output> <box2.input>";
137     info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
138     mCommandDict[info.keyword] = info;
139
140     info.keyword = "print";
141     info.argmin = 1;
142     info.argmax = 1;
143     info.code = cPrint;
144     info.syntax = "print <string>";
145     info.help = "Prints the string. Substitutes any token of the form '$box.output$' by the string adaptation of the output of the box (requires the right adaptor). No carriage return is issued at the end, use '\\n' to add carriage returns. The level of 'echo' messages must be greater than 1 (see the command 'message').";
146     mCommandDict[info.keyword] = info;
147
148     info.keyword = "exec";
149     info.argmin = 1;
150     info.argmax = 2;
151     info.code = cExec;
152     info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
153     info.help = "Executes the black box of name <box> (and connected boxes if needed). If the special keyword 'freeze' is given then freezes any further execution command. 'unfreeze' reverts to normal execution mode.";
154     mCommandDict[info.keyword] = info;
155
156     info.keyword = "package";
157     info.argmin = 1;
158     info.argmax = 1;
159     info.code = cPackage;
160     info.syntax = "package <name>";
161     info.help = "Begins the definition of a package.";
162     mCommandDict[info.keyword] = info;
163     
164     info.keyword = "endpackage";
165     info.argmin = 0;
166     info.argmax = 0;
167     info.code = cEndPackage;
168     info.syntax = "endpackage";
169     info.help = "Ends the definition of a package.";
170     mCommandDict[info.keyword] = info;
171
172     info.keyword = "define";
173     info.argmin = 1;
174     info.argmax = 2;
175     info.code = cDefine;
176     info.syntax = "define <type> [<package>]";
177     info.help = "Begins the definition of a new type of complex black box called <type>. If <package> if provided will create it in the given package.";
178     mCommandDict[info.keyword] = info;
179     
180     info.keyword = "endefine";
181     info.argmin = 0;
182     info.argmax = 0;
183     info.code = cEndDefine;
184     info.syntax = "endefine";
185     info.help = "Ends the definition of a new type of complex black box";
186     mCommandDict[info.keyword] = info;
187
188     info.keyword = "kind";
189     info.argmin = 1;
190     info.argmax = 1;
191     info.code = cKind;
192     info.syntax = "kind <ADAPTOR|DEFAULT_ADAPTOR|WIDGET_ADAPTOR|DEFAULT_WIDGET_ADAPTOR>";
193     info.help = "Sets the kind of the currently defined complex black box";
194     mCommandDict[info.keyword] = info;
195
196     info.keyword = "input";
197     info.argmin = 3;
198     info.argmax = 3;
199     info.code = cInput;
200     info.syntax = "input <name> <box.input> <help>";
201     info.help = "Defines the input <name> of the current working black box as being an alias for the input <input> of the black box <box>. <help> defines the help string for the newly created input";
202     mCommandDict[info.keyword] = info;
203
204     info.keyword = "output";
205     info.argmin = 3;
206     info.argmax = 3;
207     info.code = cOutput;
208     info.syntax = "output <name> <box.output> <help>";
209     info.help = "Defines the output <name> of the current working black box as being an alias for the output <output> of the black box <box>. <help> defines the help string for the newly created output";
210     mCommandDict[info.keyword] = info;
211
212     info.keyword = "set";
213     info.argmin = 2;
214     info.argmax = 2;
215     info.code = cSet;
216     info.syntax = "set <box.input> <value>";
217     info.help = "Sets the value of the input <input> of the black box <box> to <value>. There must exist a string to the value type adaptor";
218     mCommandDict[info.keyword] = info;
219    
220     info.keyword = "config";  // JPR
221     info.argmin = 0;
222     info.argmax = 0;
223     info.code = cConfig;
224     info.syntax = "config";
225     info.help = "Prints the value of all configuration parameters";
226     mCommandDict[info.keyword] = info;
227
228     info.keyword = "index";  // LG
229     info.argmin = 0;
230     info.argmax = 2;
231     info.code = cIndex;
232
233     info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
234     info.help = "Creates an html index of known boxes. If filename is provided then save it to the file 'filename'. The default index entries are the initial letters of the names of the boxes. If 'Packages' or 'Categories' is provided then the entries are either the packages names or the categories. If 'Adaptors' is provided then an alphabetical index of all adaptors is created.";
235     mCommandDict[info.keyword] = info;
236
237     info.keyword = "reset";  
238     info.argmin = 0;
239     info.argmax = 0;
240     info.code = cReset;
241     info.syntax = "reset";
242     info.help = "Deletes all boxes and unloads all packages (reset to start state)";
243     mCommandDict[info.keyword] = info;
244
245     info.keyword = "author";
246     info.argmin = 1;
247     info.argmax = 1;
248     info.code = cAuthor;
249     info.syntax = "author <string>";
250     info.help = "Adds the string <string> to the author information of the black box being defined";
251     mCommandDict[info.keyword] = info;
252     
253     info.keyword = "category"; //JP
254     info.argmin = 1;
255     info.argmax = 1;
256     info.code = cCategory;
257     info.syntax = "category <list of items, separated by ;>";
258     info.help = "Adds the string <string> to the category information of the black box being defined";
259     mCommandDict[info.keyword] = info;
260
261     info.keyword = "description";
262     info.argmin = 1;
263     info.argmax = 1;
264     info.code = cDescription;
265     info.syntax = "description <string>";
266     info.help = "Adds the string <string> to the descriptive information of the black box being defined";
267     mCommandDict[info.keyword] = info;
268
269     info.keyword = "help";
270     info.argmin = 0;
271     info.argmax = 2;
272     info.code = cHelp;
273     info.syntax = "help";
274     info.syntax = "\n         (1) help \n         (2) help <command name> \n         (3) help packages [all]\n         (4) help <package name> [all]\n         (5) help <black box type> \n         (6) help <black box name>";
275     info.help = "Effect :\n         (1) Lists all available commands;\n         (2) Prints help on a particular command; \n         (3) Lists the packages loaded and their black boxes.\n             Add 'all' to list adaptors; \n         (4) Prints short help on the black boxes of a package.\n             Add 'all' to include adaptors; \n         (5) Prints full help on a black box type; \n         (6) Prints information on the inputs, outputs and connections of a black box instance.";
276     mCommandDict[info.keyword] = info;
277
278     info.keyword = "message";
279     info.argmin = 0;
280     info.argmax = 2;
281     info.code = cMessage;
282     info.syntax = "message <kind> <level>";
283     info.help = "Sets the level of the kind of messages <kind> to <level>.\n  If kind='All' then sets the level for all kinds. If no kind nor level is passed then prints info on available kinds of messages and their current level.";  
284     mCommandDict[info.keyword] = info;
285
286     info.keyword = "include";
287     info.argmin = 1;
288     info.argmax = 2;
289     info.code = cInclude;
290     info.syntax = "include <filename> [source]";
291     info.help = "Includes the file <filename>.\n  'source' : If the keyword 'source' is provided then informs the interpreter that the included file is the source of the current box definition (Advanced; used to get the right 'Include' field in html doc of packages 'appli' scripts).";
292     mCommandDict[info.keyword] = info;
293
294     info.keyword = "quit";
295     info.argmin = 0;
296     info.argmax = 0;
297     info.code = cQuit;
298     info.syntax = "quit";
299     info.help = "Quits the program (during script execution it stops the complete execution)";
300     mCommandDict[info.keyword] = info;
301
302     info.keyword = "load";
303     info.argmin = 1;
304     info.argmax = 1;
305     info.code = cLoad;
306     info.syntax = "load <packagename>";
307     info.help = "Loads the black box package <packagename>";
308     mCommandDict[info.keyword] = info;
309
310     info.keyword = "unload";
311     info.argmin = 1;
312     info.argmax = 1;
313     info.code = cUnload;
314     info.syntax = "unload <packagename>";
315     info.help = "Unloads the black box package <packagename>";
316     mCommandDict[info.keyword] = info;
317
318     info.keyword = "graph";
319     info.argmin = 0;
320     info.argmax = 6;
321     info.code = cGraph;
322     info.syntax = "graph [ BlackBoxName [ Detail 0..1 [ Level 0..99999 [ Output html file [ Custom header [ Custom title ]]]]]] \n         graph [ BlackBoxNameType [ Detail 0..1 [ Level 0..99999 [ Output html file [ Custom header [ Custom title ]]]]]]";
323     info.help = "Shows a graphical view of a bbtk pipeline.\n- BlackBoxName : name of the box to view. Default '.' : current box.\n- BlackBoxNameType : name of the type of box to view, ex : 'workspace')";
324     mCommandDict[info.keyword] = info;
325
326     info.keyword = "debug";
327     info.argmin = 0;
328     info.argmax = 1;
329     info.code = cDebug;
330     info.syntax = "debug [expr|-C|-D]";
331     info.help = "Prints debug info on living bbtk objects containing the string 'expr' (default expr=''). -C checks the factory integrity. -D turns on objects debug info after main ends";
332     mCommandDict[info.keyword] = info;
333
334     /*
335     info.keyword = "workspace";
336     info.argmin = 1;
337     info.argmax = 2;
338     info.code = cWorkspace;
339     info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
340     info.help = "Configures the workspace.\n        'freeze' allow to block execution commands while keeping definition commands active. 'unfreeze' turns back the worspace in 'normal' mode.\n      'rename' allow to set a new name to the workspace.";
341     mCommandDict[info.keyword] = info;
342     */
343
344     bbtkDebugDecTab("Interpreter",9);
345
346   } 
347   //=======================================================================
348   
349   
350   
351   //=======================================================================  
352   /**
353    *  
354    */
355   Interpreter::~Interpreter()
356   {
357     bbtkDebugMessageInc("Interpreter",9,"==> Interpreter::~Interpreter()" <<std::endl);
358     mVirtualExecuter = VirtualExec::Pointer();
359     bbtkDebugMessageInc("Interpreter",9,"<== Interpreter::~Interpreter()" <<std::endl);
360   }
361   //=======================================================================
362
363
364   InterpreterError::InterpreterError( const std::string& message,
365                                       bool in_script_file,
366                                       const std::string& script_file,
367                                       int script_line 
368                                       )
369     : Exception("Interpreter",0,message),
370       mInScriptFile(in_script_file),
371       mScriptFile(script_file),
372       mScriptLine(script_line)
373   {
374   }
375   InterpreterError::InterpreterError( const Exception& excep,
376                       bool in_script_file,
377                       const std::string& script_file,
378                       int script_line 
379                       )
380     : Exception(excep),
381       mInScriptFile(in_script_file),
382       mScriptFile(script_file),
383       mScriptLine(script_line)
384   {
385   }
386   //=======================================================================
387   void Interpreter::CatchBbtkException( const bbtk::Exception& e )
388   {
389     if (mThrow) 
390       {
391         bool in_script = false;
392         std::string file("");
393         int line = 0;
394         if (mFileName.size()) {
395           std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
396           if (fs!=0) in_script = true;    
397           file = mFileName.back();
398           line = mLine.back();
399         }   
400         CloseAllFiles();
401         throw InterpreterError(e,in_script,file,line);
402       }
403     else
404       {
405         std::stringstream mess;
406         mess << "* ERROR : "<<e.GetMessage()<<std::endl;
407         if (mFileName.size()) {
408           mess << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
409           mess << "* LINE  : "<<mLine.back()<<std::endl;
410         }    
411         std::cerr << mess.str();
412       }
413   }
414   //=======================================================================
415   
416   //=======================================================================
417   void Interpreter::CatchStdException( const std::exception& e )
418   {  
419     if (mThrow) 
420       {
421         bool in_script = false;
422         std::string file("");
423         int line = 0;
424         if (mFileName.size()) {
425           std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
426           if (fs!=0) in_script = true;    
427           file = mFileName.back();
428           line = mLine.back();
429         }    
430         CloseAllFiles();
431         throw InterpreterError(e.what(),in_script,file,line);
432       }
433     else
434       {
435         std::stringstream mess;
436         mess << "* ERROR : "<<e.what()<<std::endl;
437         if (mFileName.size()) {
438           mess << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
439           mess << "* LINE  : "<<mLine.back()<<std::endl;
440         }    
441         std::cerr << mess.str();
442       }
443   }
444   //=======================================================================
445
446   //=======================================================================
447   void Interpreter::CatchUnknownException()
448   {
449     if (mThrow) 
450       {
451         bool in_script = false;
452         std::string file("");
453         int line = 0;
454         if (mFileName.size()) {
455           std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
456           if (fs!=0) in_script = true;    
457           file = mFileName.back();
458           line = mLine.back();
459         }    
460         CloseAllFiles();
461         throw InterpreterError("Unknown exception caught",
462                                    in_script,file,line);
463       }
464     else
465       {
466         std::stringstream mess;
467         mess << "* UNDEFINED ERROR (not a bbtk nor a std exception)" 
468              << std::endl;
469         if (mFileName.size()) {
470           mess << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
471           mess << "* LINE  : "<<mLine.back()<<std::endl;
472         }    
473         std::cerr << mess.str();
474       }
475   }
476   //=======================================================================
477
478   //=======================================================================
479
480 #define CATCH_MACRO                             \
481   catch (QuitException e)                       \
482     {                                           \
483       status = Interpreter_QUIT;                \
484       if (mThrow) throw QuitException();        \
485     }                                           \
486   catch (bbtk::Exception e)                     \
487     {                                           \
488       status = Interpreter_ERROR;               \
489       CatchBbtkException(e);                    \
490     }                                           \
491   catch (std::exception& e)                     \
492     {                                           \
493       status = Interpreter_ERROR;               \
494       CatchStdException(e);                     \
495     }                                           \
496   catch (...)                                   \
497     {                                           \
498       status = Interpreter_ERROR;               \
499       CatchUnknownException();                  \
500     }                                           
501   //=======================================================================
502    
503
504   //=======================================================================
505   /**
506    *  
507    */
508   Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
509   {
510     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
511
512     bool exm = mCommandLine;
513     mCommandLine = false;
514
515     ExitStatus status = Interpreter_OK;
516
517     try 
518     {
519       SwitchToFile(filename);
520
521       bool insideComment = false; // for multiline comment
522       while (mFile.size()>0) 
523       {
524         while (!mFile.back()->eof()) {
525           mLine.back()++;
526           char buf[500];
527           mFile.back()->getline(buf,500);
528           std::string str(buf);
529           int size=str.length();
530           if ( str[ size-1 ]==13  )
531             {
532               str.erase(size-1,1);
533             }
534           
535           InterpretLine(str, insideComment);
536           
537        }//while
538        CloseCurrentFile();
539       }
540     }
541     CATCH_MACRO;
542     
543     CloseAllFiles();
544     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
545     bbtkDecTab("Interpreter",9);
546
547     mCommandLine = exm;
548     
549     return status;
550   }
551   //=======================================================================
552
553
554   //=======================================================================
555   /**
556    *  
557    */
558   Interpreter::ExitStatus 
559   Interpreter::InterpretBuffer( std::stringstream* buffer )
560   {
561     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
562
563     bool exm = mCommandLine;
564     mCommandLine = false;
565
566     ExitStatus status = Interpreter_OK;
567
568     try 
569     {
570       SwitchToStream(buffer);
571       bool insideComment = false; // for multiline comment
572       while (mFile.size()>0) 
573       {
574         while (!mFile.back()->eof()) {
575           mLine.back()++;
576           char buf[500];
577           mFile.back()->getline(buf,500);
578           std::string str(buf);
579           
580           int size=str.length();
581           if ( str[ size-1 ]==13  )
582             {
583               str.erase(size-1,1);
584             }
585           
586           InterpretLine(str, insideComment);
587           
588         }//while
589         
590         CloseCurrentFile();
591       }
592     }
593     CATCH_MACRO;
594     
595     CloseAllFiles();
596     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
597     bbtkDecTab("Interpreter",9);
598     
599     mCommandLine = exm;
600     return status;
601   }
602   //=======================================================================
603
604   //=======================================================================
605   /// Runs the interpretation of a command
606   Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
607   {
608     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
609
610     ExitStatus status = Interpreter_OK;
611
612     try 
613     {
614       bool insideComment = false;
615       InterpretLine(line, insideComment);
616     }
617     CATCH_MACRO;
618   
619
620     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
621                      <<std::endl);
622     bbtkDecTab("Interpreter",9);
623     
624     return status;
625   }
626   
627
628   //=======================================================================  
629   /**
630    *
631    */
632 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
633 {
634     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
635     bbtkMessage("echo",2,line<<std::endl);
636
637     std::vector<std::string> words;
638     SplitLine(line,words);
639
640     // Empty line
641     if (words.size()<1) 
642     {
643        bbtkDebugDecTab("Interpreter",9);
644        return;
645     }
646
647     // Single line comment : # or //
648     if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') ) 
649     {  
650        bbtkDebugDecTab("Interpreter",9);
651        bbtkMessage("Interpreter",9,"Comment"<<std::endl);
652        return;
653     }
654
655     // Multi line comment ( /* ... */ ) -delimiters on different lines !-
656     
657     if (words[0][0]=='/' && words[0][1]=='*') 
658     {  
659        bbtkDebugDecTab("Interpreter",9);
660        bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
661        insideComment = true;
662        return;
663     }
664
665     if (words[0][0]=='*' && words[0][1]=='/') 
666     {  
667        bbtkDebugDecTab("Interpreter",9);
668        bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
669        if ( !insideComment ) {
670           bbtkDebugDecTab("Interpreter",9);
671           bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);       
672        }
673        insideComment = false;
674        return;
675     }
676
677     if (insideComment) 
678     {  
679        bbtkDebugDecTab("Interpreter",9);
680        bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
681        return;
682     }
683
684     // Command 
685     CommandInfoType command;
686     InterpretCommand(words,command);
687
688     bbtkDebugMessage("Interpreter",9,
689                      "Command='"<<command.keyword
690                       <<"' code="<<command.code<<std::endl); 
691     int level=0;
692     std::string left,right,left2,right2;
693     std::string filename;
694     switch (command.code) 
695     {
696       case cNew :
697         mVirtualExecuter->Create(words[1],words[2]);
698         break;
699
700       case cDelete :
701         mVirtualExecuter->Destroy(words[1]);
702         break;
703
704       case cConnect :
705         Utilities::SplitAroundFirstDot(words[1],left,right);
706         Utilities::SplitAroundFirstDot(words[2],left2,right2);      
707         mVirtualExecuter->Connect(left,right,left2,right2);
708         break;
709
710       case cPackage :
711         mVirtualExecuter->BeginPackage(words[1]);
712         break;
713
714       case cEndPackage :
715         mVirtualExecuter->EndPackage();
716         break;
717
718       case cDefine :
719         if (mFileName.size()>0) 
720         {
721           filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
722         }
723         if (words.size()==2) 
724         {
725            mVirtualExecuter->Define(words[1],"",filename);
726         }
727         else
728         {
729            mVirtualExecuter->Define(words[1],words[2],filename);
730         }
731         break;
732
733       case cEndDefine :
734         mVirtualExecuter->EndDefine();
735         break;
736
737       case cKind :
738         mVirtualExecuter->Kind(words[1]);
739         break;
740
741       case cPrint :
742         mVirtualExecuter->Print(words[1]);
743         break;
744         
745       case cExec :
746         if (words[1]=="freeze") 
747           mVirtualExecuter->SetNoExecMode(true);
748         else if (words[1]=="unfreeze") 
749           mVirtualExecuter->SetNoExecMode(false);
750         else
751           mVirtualExecuter->Execute(words[1]);
752         break;
753
754       case cInput :
755         Utilities::SplitAroundFirstDot(words[2],left,right);
756         mVirtualExecuter->DefineInput(words[1],left,right,words[3]);
757         break;
758
759       case cOutput :
760         Utilities::SplitAroundFirstDot(words[2],left,right);
761         mVirtualExecuter->DefineOutput(words[1],left,right,words[3]);
762         break;
763
764       case cSet :
765         Utilities::SplitAroundFirstDot(words[1],left,right);
766         mVirtualExecuter->Set(left,right,words[2]);
767         break;
768
769       case cAuthor :
770         mVirtualExecuter->Author(words[1]);
771         break;
772
773       case cNewGUI :
774         NewGUI(words[1],words[2]);
775         break;
776
777       case cCategory :
778         mVirtualExecuter->Category(words[1]);
779         break;
780
781       case cIndex :
782         if (words.size()==1)
783              Index("tmp_index.html");
784         else if (words.size()==2)
785              Index(words[1]);
786         else if (words.size()==3)
787              Index(words[1],words[2]);
788         break;
789
790       case cDescription :
791         mVirtualExecuter->Description(words[1]);
792         break;
793
794       case cHelp :
795         Help(words);
796         break;
797
798       case cMessage : 
799         if (words.size()<3)
800         {
801           mVirtualExecuter->HelpMessages();
802         }
803         else
804         {
805           sscanf(words[2].c_str(),"%d",&level);
806           mVirtualExecuter->SetMessageLevel(words[1],level);
807         }
808         break;
809
810       case cGraph :
811         Graph(words);
812         break;
813
814       case cConfig :
815         Config();
816         break;
817
818       case cReset :  
819         Reset();
820         break;
821
822       case cInclude :
823         if (mCommandLine)
824         {
825            InterpretFile(words[1]); 
826         }
827         else
828         {
829             SwitchToFile(words[1]);
830         }
831         // if 'source' was given
832         if (words.size()==3) 
833           {
834             GetExecuter()->SetCurrentFileName(words[1]);
835           }
836         break;
837
838       case cLoad:
839         GetExecuter()->LoadPackage(words[1]);
840         break;
841
842       case cUnload:
843         GetExecuter()->UnLoadPackage(words[1]);
844         break;
845
846       case cQuit :
847         throw QuitException();
848         break;
849
850       case cDebug :
851         if (words.size()==2) Debug(words[1]);
852         else Debug("");
853         break;
854         /* obsolete
855       case cWorkspace :
856         if (words.size() == 2) 
857         {
858            if (words[1]=="freeze")        mVirtualExecuter->SetNoExecMode(true);
859            else if (words[1]=="unfreeze") mVirtualExecuter->SetNoExecMode(false);
860         }
861         else
862         {
863            mVirtualExecuter->SetWorkspaceName(words[2]);
864         }
865         break;
866         */
867       default:
868         bbtkInternalError("should not reach here !!!");
869    }
870
871    bbtkDecTab("Interpreter",9);
872 }
873   //=======================================================================  
874
875
876
877
878
879   //=======================================================================
880   /**
881    *
882    */
883 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
884 {
885     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
886
887     std::string delimiters = "\"";
888     std::vector<std::string> quote;
889     Utilities::SplitString(str,delimiters,quote);
890
891     delimiters = " \t";
892     std::vector<std::string>::iterator i;
893     for (i=quote.begin(); i!=quote.end(); ) 
894     {
895        Utilities::SplitString(*i,delimiters,tokens);
896        ++i;
897        if (i!=quote.end()) 
898        {
899         //    bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
900           tokens.push_back(*i);
901           ++i;
902        }
903     }
904
905     for (i=tokens.begin(); i!=tokens.end(); ++i) 
906     {
907        bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
908     }
909     bbtkDebugMessageCont("Interpreter",9,std::endl);
910
911     bbtkDebugDecTab("Interpreter",9);
912  }
913   //=======================================================================
914
915
916   //=======================================================================
917   void Interpreter::Reset()
918   {
919     // Cannot close all files if the reset command is read from a file !
920     //    CloseAllFiles();
921     mFileNameHistory.clear();
922     this->mVirtualExecuter->Reset();
923   }
924   //=======================================================================
925
926   //=======================================================================
927   /**
928    *
929    */
930   /*
931   void Interpreter::Print( const std::string& str)
932   {
933     if (mVirtualExecuter->GetNoExecMode()) return;
934
935     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
936
937  // TO DO :
938  // InterpretLine ("load std")
939  // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande 
940  // InterpretLine("new Print _P_") 
941  // InterpretLine("connect _C_.Out _P_.In")
942  // int num = 1
943  
944
945     std::vector<std::string> chains;
946     std::string delimiters("$");
947
948     // Skip delimiters at beginning.
949     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
950     bool is_text = true;
951     if (lastPos>0) is_text = false;
952
953     // Find first delimiter.
954     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
955
956     while (std::string::npos != pos || std::string::npos != lastPos)
957     {
958        if (is_text) 
959        {
960           // Found a text token, add it to the vector.
961           chains.push_back(str.substr(lastPos, pos - lastPos));
962  // std::string token = str.substr(lastPos, pos - lastPos)
963  // InterpretLine("set _C_.In%num% %token%")
964  
965        }
966        else 
967        {
968
969        // is an output (between $$) : decode 
970          std::string tok,box,output;
971          tok = str.substr(lastPos, pos - lastPos);
972          Utilities::SplitAroundFirstDot(tok,box,output);
973          chains.push_back( mVirtualExecuter->Get(box,output) );
974
975 // InterpretLine("connect %tok% _C_.In%num%") 
976
977        }
978         // Skip delimiters.  Note the "not_of"
979        lastPos = str.find_first_not_of(delimiters, pos);
980         // Find next delimiter
981        pos = str.find_first_of(delimiters, lastPos);
982     //
983        is_text = !is_text;
984 // num ++;
985      }
986 // InterpretLine("exec _P_")
987 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
988
989      std::vector<std::string>::iterator i;
990      for (i= chains.begin(); i!=chains.end(); ++i) 
991      {
992
993        Utilities::SubsBackslashN(*i);
994        std::cout << *i;
995      }
996      std::cout << std::endl;
997      bbtkDebugDecTab("Interpreter",9);
998  }
999 */
1000
1001   //=======================================================================
1002   /**
1003    *
1004    */
1005
1006   // =========================================================================
1007   void Interpreter::SwitchToFile( const std::string& name )
1008   {
1009   // Note : in the following :
1010   // name : the user supplied name 
1011   //      - abreviated name    e.g.       scr   scr.bbs
1012   //      - relative full name e.g.       ./scr.bbs   ../../scr.bbs 
1013   //      - absolute full name e.g.       /home/usrname/proj/dir/scr.bbs
1014   //          same for Windows, with      c:, d: ...
1015   //
1016   // use ./directory/subdir/scrname.bbs
1017   //
1018
1019     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
1020                          <<name<<"\")"<<std::endl);
1021
1022     std::vector<std::string> script_paths;
1023     std::string fullPathScriptName;  // full path script name
1024     std::string pkgname;             // e.g. <scriptname>.bbs
1025     std::vector<std::string> Filenames;
1026
1027     // The following is *NOT* a debug time message :
1028     // It's a user intended message.
1029     // Please don't remove it.
1030     bbtkMessage("Interpreter",1,
1031         "look for : [" << name
1032         << "]" << std::endl);
1033
1034
1035     std::string upath;
1036     pkgname = Utilities::ExtractScriptName(name,upath);
1037
1038     bbtkMessage("Interpreter",3,
1039                 "extract : pkgname [" << pkgname
1040                  << "] upath [" << upath << "]" << std::endl);
1041     bool fullnameGiven = false; 
1042     bool foundFile     = false;
1043
1044     // ==== "*" provided : load all scripts in given path 
1045     // relative (e.g. std/boxes/*) or absolute 
1046     if (pkgname == "*") 
1047       {
1048         int nbBssFiles;
1049         
1050         std::stringstream* stream = new std::stringstream;
1051         //if (upath.size()!=0) // avoid troubles for "*"
1052         
1053         // ==== no path provided : look in root bbs path
1054         if (upath.size()==0)
1055           {
1056             //      bbtkMessage("Interpreter",1,
1057             script_paths.push_back(  ConfigurationFile::GetInstance().Get_root_bbs_path() );
1058           }
1059         // ==== absolute path provided 
1060         else if (upath[0]=='/' || upath[1] == ':' ) 
1061           {
1062             if ( Utilities::IsDirectory( upath ) )
1063               {
1064                 script_paths.push_back(upath);
1065               }
1066             else 
1067               {
1068                 bbtkError("'"<<upath<<"' : directory does not exist"); 
1069               }
1070           }
1071         // ==== relative path provided : search all bbs path appended with 
1072         // the relative path provided
1073         else
1074           {    
1075              std::vector<std::string>::const_iterator i;
1076              for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1077                   i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1078                   i++)
1079                {
1080                  std::string full_path(*i);
1081                  // we *really* want '.' to be the current working directory
1082                  if (full_path == ".") {
1083                    char buf[2048]; // for getcwd
1084                    char * currentDir = getcwd(buf, 2048);
1085                    std::string cwd(currentDir);
1086                    full_path = currentDir;
1087                  } // if full_path
1088             
1089                  full_path += ConfigurationFile::GetInstance().Get_file_separator();
1090                  full_path += upath;
1091
1092                  if ( Utilities::IsDirectory( full_path ) )
1093                    {
1094                      script_paths.push_back(full_path);
1095                    }
1096                } 
1097              if (script_paths.empty())
1098                {
1099                  bbtkError("no '"<<upath<<"' subdir found in search paths" 
1100                            << std::endl);
1101                }
1102
1103           }
1104         // === search paths list complete : now explore it
1105
1106
1107         std::vector<std::string>::iterator i;
1108         for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1109           {
1110             bbtkMessage("Interpreter",1,
1111                         "--> Looking in '" << *i << "'" << std::endl);
1112          
1113             
1114             Filenames.clear();
1115             int nbFiles = Utilities::Explore(*i, false, Filenames);
1116             
1117             nbBssFiles = 0;
1118             for (std::vector<std::string>::iterator j = Filenames.begin(); 
1119                  j!= Filenames.end(); ++j)
1120               {
1121                 int lgr = (*j).size();
1122                 if (lgr < 5)
1123                   continue;  // ignore non .bbs file
1124                 if ((*j).substr(lgr-4, 4) != ".bbs")
1125                   continue;
1126                 
1127                 (*stream) << "include \"" << *j << "\"\n";
1128                 bbtkMessage("Interpreter",2,
1129                             "  --> Found '" << *j << "'" << std::endl);
1130                 
1131                 nbBssFiles++;
1132               } // for vector
1133             
1134             if (nbBssFiles==0)
1135               {
1136                 bbtkMessage("Interpreter",1,
1137                             "  --> No .bbs found"<< std::endl);
1138               } 
1139             else 
1140               {
1141                 bbtkMessage("Interpreter",1,
1142                             "  --> "<<nbBssFiles<<" .bbs found"<< std::endl);
1143                 SwitchToStream(stream);
1144               }
1145             
1146             //break; // a directory was found; we stop iterating
1147             // LG : No! We want all files included !
1148           } // for vector
1149         return;
1150       }  
1151     //=============== end pkgname=="*" ===========
1152
1153
1154     // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1155     // (not only a plain script name)
1156     // we trust him, and try to expland the directory name
1157     // WARNING : starting from current local directory :  ./whatYouWant  (./ mandatory!)
1158
1159     if (name[0]=='/' || name[1] == ':' || name[0]=='.')  // absolute path (linux/windows) or relative path
1160     { 
1161
1162       // ===========================================================check user supplied location
1163       fullnameGiven = true;
1164
1165       fullPathScriptName =  Utilities::ExpandLibName(name, false);
1166
1167       // allow user to always forget ".bbs"
1168       int l = fullPathScriptName.size();
1169
1170       if (l!=0) {
1171
1172       if (l>4)
1173       {
1174          if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1175          {
1176             fullPathScriptName = fullPathScriptName + ".bbs";
1177          }
1178       }
1179       else
1180       {
1181          fullPathScriptName = fullPathScriptName + ".bbs";   
1182       }
1183
1184       if ( Utilities::FileExists(fullPathScriptName))
1185       {
1186         foundFile = true;
1187       }
1188     } // endif l != 0
1189   }
1190   else
1191     // =============================== iterate on the paths
1192     {
1193       script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1194       std::string path;
1195       std::vector<std::string>::iterator i;
1196       for (i=script_paths.begin();i!=script_paths.end();++i)
1197         {
1198           path = *i;
1199           // we *really* want '.' to be the current working directory
1200           if (path == ".") {
1201             char buf[2048]; // for getcwd
1202             char * currentDir = getcwd(buf, 2048);
1203             std::string cwd(currentDir);
1204             path = currentDir;
1205           }
1206           
1207           fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1208           
1209           // Check if library exists
1210           if ( ! Utilities::FileExists(fullPathScriptName) )
1211             {
1212               // The following is *NOT* a debug time message :
1213               // It's a user intended message.
1214               // Please don't remove it.
1215               bbtkMessage("Interpreter",2,
1216                           "   [" <<fullPathScriptName <<"] : doesn't exist" 
1217                           <<std::endl);
1218               continue;  // try next path
1219             }
1220           bbtkMessage("Interpreter",2,
1221                       "   [" <<fullPathScriptName 
1222                       <<"] : found" <<std::endl);
1223           foundFile = true;
1224           break; // a script was found; we stop iterating
1225
1226         } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1227     }
1228     
1229     if (!foundFile)
1230       {
1231         if (fullnameGiven)
1232           if(fullPathScriptName == "")
1233             bbtkError("Path ["<<upath<<"] doesn't exist");
1234           else
1235             bbtkError("Script ["<<fullPathScriptName<<"] not found");
1236         else
1237           bbtkError("No ["<<pkgname<<".bbs] script found");
1238         return;
1239       }
1240     else
1241       LoadScript(fullPathScriptName,name);
1242     
1243     return;
1244   }
1245   //=======================================================================
1246
1247
1248   //=======================================================================
1249 void Interpreter::SwitchToStream( std::stringstream* stream )
1250 {
1251     mFile.push_back(stream);
1252     std::ostringstream buffer_name;
1253     bufferNb++;
1254     buffer_name << "buffer_" ;
1255
1256     if (mFileName.size()>0 )
1257     {
1258        buffer_name << mFileName.back() << "_" << mLine.back();
1259     }
1260     mFileName.push_back(buffer_name.str());
1261     mIncludeFileName.push_back(buffer_name.str());
1262     mLine.push_back(0);
1263 }
1264   //=======================================================================
1265
1266   //=======================================================================
1267
1268   void Interpreter::LoadScript( std::string fullPathScriptName,
1269                                 std::string includeScriptName)
1270   {
1271      Utilities::replace( fullPathScriptName , 
1272                          INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1273    
1274      if (find(mFileNameHistory.begin(),
1275               mFileNameHistory.end(),
1276               fullPathScriptName)!=mFileNameHistory.end())
1277      {
1278         return;
1279      }
1280
1281     std::ifstream* s;
1282     s = new std::ifstream;
1283     s->open(fullPathScriptName.c_str());
1284     if (!s->good())
1285     {
1286         bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1287         return;
1288     }
1289
1290     bbtkMessage("Interpreter",1,"   -->[" << fullPathScriptName 
1291                 << "] found" << std::endl);
1292
1293     mFile.push_back(s);
1294     mFileName.push_back(fullPathScriptName);
1295     mFileNameHistory.push_back(fullPathScriptName);
1296     mIncludeFileName.push_back(includeScriptName);
1297     mLine.push_back(0);
1298
1299     return;
1300   }
1301
1302   //=======================================================================
1303   /**
1304    *  
1305    */
1306   void Interpreter::CloseCurrentFile()
1307   {
1308     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1309                       <<std::endl);
1310
1311     if (mFile.size()==0)
1312     {
1313       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1314       return;
1315     }
1316
1317     bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1318
1319     std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1320     if (file!=0) file->close();
1321
1322     delete mFile.back();
1323     mFile.pop_back();
1324     mFileName.pop_back();
1325     mIncludeFileName.pop_back();
1326     mLine.pop_back();
1327
1328     bbtkDebugMessage("Interpreter",9," Remains "
1329                      <<mFile.size()
1330                      <<" open"<<std::endl);
1331     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1332                      <<std::endl);
1333   }
1334   //=======================================================================
1335
1336  //=======================================================================
1337   /**
1338    *  
1339    */
1340   void Interpreter::CloseAllFiles()
1341   {
1342     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1343                       <<std::endl);
1344
1345     while (mFile.size() != 0) 
1346     {
1347        CloseCurrentFile();
1348     }
1349     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1350                       <<std::endl);
1351   }
1352   //=======================================================================
1353
1354
1355
1356   //=======================================================================
1357   /**
1358    *  
1359    */
1360   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1361                                       CommandInfoType& info )
1362   {
1363     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1364
1365     // searches the command keyword
1366     CommandDictType::iterator c;
1367     c = mCommandDict.find(words[0]);
1368     if ( c == mCommandDict.end() ) {
1369       bbtkError(words[0]<<" : unknown command");
1370     }
1371
1372     // tests the number of args 
1373     if ( ( words.size()-1 < c->second.argmin ) ||
1374          ( words.size()-1 > c->second.argmax ) )
1375     {
1376        HelpCommand(words[0]);
1377        bbtkError(words[0]<<" : wrong number of arguments");
1378     }
1379
1380     info = c->second;
1381     bbtkDecTab("Interpreter",9);
1382   }
1383   //=======================================================================
1384
1385
1386   //=======================================================================
1387   /// Displays help on all the commands
1388 void Interpreter::Help(const std::vector<std::string>& words)
1389 {
1390     unsigned int nbarg = words.size()-1;
1391
1392     if (nbarg==0) 
1393     {
1394        HelpCommands();
1395     }
1396     else if (nbarg==1) 
1397     {
1398       if (words[1]=="packages") 
1399       {
1400          GetExecuter()->GetFactory()->PrintPackages(true);
1401          return;
1402       }
1403       try 
1404       {
1405           HelpCommand(words[1]);
1406       }
1407       catch (bbtk::Exception e) 
1408       {
1409          try 
1410          {
1411             GetExecuter()->GetFactory()->HelpPackage(words[1]);
1412             if ( mUser != 0 )
1413               {
1414                 std::string url = 
1415                   ConfigurationFile::GetInstance().Get_doc_path();
1416                 url += "/bbdoc/" + words[1] + "/index.html";
1417                 if (Utilities::FileExists(url)) 
1418                   {
1419                     mUser->InterpreterUserViewHtmlPage(url);
1420                   }
1421               }
1422          }
1423          catch (bbtk::Exception f) 
1424          {
1425            try 
1426              {
1427                std::string package;
1428                GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1429                if ( mUser != 0 )
1430                  {
1431                    std::string url = 
1432                      ConfigurationFile::GetInstance().Get_doc_path();
1433                    url += "/bbdoc/" + package + "/index.html";
1434                    if (Utilities::FileExists(url)) 
1435                      {
1436                        url += "#" + words[1];
1437                        mUser->InterpreterUserViewHtmlPage(url);
1438                      }
1439                  }
1440              }
1441            catch (bbtk::Exception g) 
1442              {
1443                try
1444                  {
1445                    GetExecuter()->ShowRelations(words[1],"0","9999");
1446                  }
1447                catch (bbtk::Exception h){
1448                  bbtkError("\""<<words[1].c_str()
1449                            <<"\" is not a known command, package, black box type or black box name");
1450                }
1451              }
1452          }
1453       }
1454     }
1455     else if (nbarg==2) 
1456     {
1457       if (words[2]=="all")
1458       {
1459          if ( words[1]=="packages" )
1460          {
1461             GetExecuter()->GetFactory()->PrintPackages(true,true);
1462             return;
1463           }
1464          try 
1465          {
1466             GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1467          }
1468          catch (bbtk::Exception f) 
1469          {
1470          }
1471      }
1472      else 
1473      {
1474         HelpCommand(words[0]);
1475         bbtkError(words[0]<<" : syntax error");
1476      }
1477   }
1478   else 
1479   {
1480      bbtkError("Should not reach here !!!");
1481   }
1482 }
1483   //=======================================================================
1484
1485    //===================================================================    
1486   /// Displays the Configuration
1487   void Interpreter::Config() const
1488   {
1489     ConfigurationFile::GetInstance().GetHelp(1);
1490   }  
1491    //===================================================================    
1492
1493   //=======================================================================
1494   /// Displays help on all the commands
1495   void Interpreter::HelpCommands()
1496   {
1497     std::cout << "Available commands :" << std::endl;
1498     CommandDictType::iterator i;
1499     for ( i =  mCommandDict.begin();
1500           i != mCommandDict.end();
1501         ++i) {
1502               std::cout << " " << i->first << std::endl;
1503       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1504       //     std::cout << "    " << i->second.help << std::endl;
1505
1506     }
1507   }
1508   //=======================================================================
1509
1510
1511   //=======================================================================
1512   /// Displays help on a particular commands
1513   void Interpreter::HelpCommand(const std::string& s)
1514   {
1515     CommandDictType::iterator c;
1516     c = mCommandDict.find(s);
1517     if ( c == mCommandDict.end() ) {
1518       bbtkError(s<<" : Unknown command");
1519     }
1520     //    std::cout << " " << s << " : "<<  std::endl;
1521     //    CommandParamDictType::iterator i;
1522     //    for ( i =  c->second.begin();
1523     //      i != c->second.end();
1524     //      ++i) {
1525     std::cout << " usage : " << c->second.syntax << std::endl;
1526     std::cout << "  " << c->second.help << std::endl;
1527
1528   }
1529   //=======================================================================
1530
1531
1532   //=======================================================================
1533   /// Fills the vector commands with the commands which 
1534   /// have the first n chars of buf for prefix
1535   /// TODO : skip initial spaces in buf and also return the position of first
1536   /// non blank char in buf
1537   void Interpreter::FindCommandsWithPrefix( char* buf,
1538                                             int n,
1539                                             std::vector<std::string>& commands )
1540   {
1541     CommandDictType::const_iterator i;
1542     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1543     {
1544       if ((i->first).find(buf,0,n) == 0) 
1545         commands.push_back(i->first);
1546     }
1547   }
1548   //=======================================================================
1549
1550
1551
1552   //=======================================================================
1553 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1554   
1555   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1556   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1557   
1558   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1559   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1560   // E.G. STORE THIS IN bbtk_config.xml
1561 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1562 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1563 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1564 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1565 #define BBTK_BACKSPACE_KBCODE   0x00000008
1566 #define BBTK_DEL_KBCODE         0x0000007F
1567 #define BBTK_SPACE_KBCODE       0x00000020 
1568
1569   //=======================================================================
1570   void Interpreter::GetLineFromPrompt(std::string& s)
1571   {
1572     int c;
1573     int ind=0;
1574
1575     int MAX_LINE_SIZE = 160;
1576     int MAX_HISTORY_SIZE = 100;
1577
1578     char* newline = new char[MAX_LINE_SIZE];
1579     memset(newline,0,MAX_LINE_SIZE);
1580     char* histline = new char[MAX_LINE_SIZE];
1581     memset(histline,0,MAX_LINE_SIZE);
1582
1583     char* line = newline;
1584     int hist = mHistory.size();
1585
1586     write(1,"> ",2);
1587     while(1)
1588     {
1589        c=0;
1590        read ( STDIN_FILENO, &c, 4) ;
1591
1592        bbtkDebugMessage("debug",9,"[0x"<<std::hex<<c<<"]\n");
1593
1594        // Printable character
1595        if ( (ind<MAX_LINE_SIZE-1) &&
1596             ( c >= BBTK_SPACE_KBCODE ) && 
1597             ( c <  BBTK_DEL_KBCODE )) 
1598        {
1599           PrintChar(c);
1600           line[ind++]=c;
1601        }
1602       // CR
1603        else if (c=='\n')
1604        {
1605        // delete the unused line
1606           if (line==newline)
1607               delete histline;
1608           else
1609               delete newline;
1610    
1611     // empty lines are not stored in from history
1612           if (strlen(line)) 
1613           {
1614              // if history too long : delete oldest command
1615              if (mHistory.size()>MAX_HISTORY_SIZE) 
1616              {
1617                 delete mHistory.front();
1618                 mHistory.pop_front();
1619              }
1620              mHistory.push_back(line);
1621           }
1622           break;
1623         }
1624        // Backspace
1625         else if ( (ind>0) && 
1626                   ((c == BBTK_BACKSPACE_KBCODE) ||
1627                    (c == BBTK_DEL_KBCODE)) )
1628           {
1629             line[ind--]=' ';
1630             BackSpace();
1631           }
1632         // Tab 
1633         else if (c=='\t')
1634           {
1635             // TODO : Command completion  
1636             std::vector<std::string> commands;
1637             FindCommandsWithPrefix( line,ind,commands);
1638             if (commands.size()==1) 
1639               {
1640                 std::string com = *commands.begin();
1641                 for (; ind<com.size(); ++ind) 
1642                   {
1643                     PrintChar(com[ind]); 
1644                     line[ind]=com[ind];
1645                   }
1646                 PrintChar(' '); 
1647                 line[ind++]=' ';
1648               }
1649             else if (commands.size()>1) 
1650               {
1651                 std::vector<std::string>::iterator i;
1652                 write(1,"\n",1);
1653                 for (i=commands.begin();i!=commands.end();++i) 
1654                   {
1655                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1656                     PrintChar(' ');
1657                   }
1658                 write(STDOUT_FILENO,"\n> ",3);
1659                 //for (int j=0;j<ind;++j) 
1660                   //{
1661                     write(STDOUT_FILENO,line,ind); 
1662                     //  }
1663               }
1664           }
1665         // Arrow up : back in history
1666         else if (c==BBTK_UP_ARROW_KBCODE)
1667           {
1668             if (hist) 
1669               {
1670                 // erase current line
1671                 while (ind--) BackSpace();
1672                 // 
1673                 hist--;
1674                 // 
1675                 strcpy(histline,mHistory[hist]);
1676                 line = histline;
1677                 ind = strlen(line);
1678                 
1679                 write(STDOUT_FILENO,line,ind);
1680               }
1681           }
1682         // Arrow down : down in history
1683         else if (c==BBTK_DOWN_ARROW_KBCODE)
1684           {
1685             if (hist<mHistory.size()-1) 
1686               {
1687                 // erase current line
1688                 while (ind--) BackSpace();
1689                 // 
1690                 hist++;
1691                 // 
1692                 strcpy(histline,mHistory[hist]);
1693                 line = histline;
1694                 ind = strlen(line);
1695                 
1696                 write(STDOUT_FILENO,line,ind);
1697               }
1698             // end of history : switch back to newline
1699             else if (hist==mHistory.size()-1)
1700               {
1701                 // erase current line
1702                 while (ind--) BackSpace();
1703                 // 
1704                 hist++;
1705                 // 
1706                 line = newline;
1707                 ind = strlen(line);
1708                 
1709                 write(STDOUT_FILENO,line,ind);
1710               }
1711           }
1712         // Arrow right
1713         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1714           {
1715             PrintChar(line[ind]);
1716             ind++;
1717           }
1718
1719         // Arrow left
1720         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1721           {
1722             PrintChar('\b');
1723             ind--;
1724     
1725           }
1726
1727       }
1728     write(STDOUT_FILENO,"\n\r",2);
1729     
1730     
1731     s = line;
1732     
1733   }
1734 #else
1735
1736   //=======================================================================
1737   void Interpreter::GetLineFromPrompt(std::string& s)
1738   {  
1739     s.clear();
1740
1741     putchar('>');
1742     putchar(' ');
1743
1744     do 
1745     {
1746       char c = getchar();
1747       if (c=='\n') 
1748       {
1749         putchar('\n');
1750         break;
1751       }
1752       if (c=='\t') 
1753       {
1754         // putchar('T');
1755         continue;
1756       }
1757       // putchar(c);
1758       s += c;
1759     } 
1760     while (true);  
1761     
1762   }
1763   //=======================================================================  
1764
1765 #endif
1766
1767
1768
1769   //=======================================================================
1770   void Interpreter::CommandLineInterpreter()
1771   {
1772     bbtkDebugMessageInc("Interpreter",9,
1773                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1774
1775 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1776     // Initialise the tty in non canonical mode with no echo
1777     // oter remembers the previous settings to restore them after 
1778     struct termios ter,oter;
1779     tcgetattr(0,&ter);
1780     oter=ter;
1781     ter.c_lflag &= ~ECHO;
1782     ter.c_lflag &= ~ICANON;
1783     ter.c_cc[VMIN]=1;
1784     ter.c_cc[VTIME]=0;
1785     tcsetattr(0,TCSANOW,&ter);
1786 #endif
1787     
1788     mCommandLine = true;
1789     bool again = true;
1790     bool insideComment = false; // for multiline comment  
1791     do 
1792     {
1793       try
1794       {
1795         std::string line;
1796         GetLineFromPrompt(line);
1797         InterpretLine(line, insideComment);
1798       }
1799       catch (QuitException e)
1800       {
1801         bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1802         again = false;
1803       }
1804       catch (bbtk::Exception e) 
1805       {
1806         e.Print();
1807       }
1808         catch (std::exception& e) 
1809       {
1810         std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1811       }
1812       catch (...)
1813       {
1814         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1815       }
1816     }
1817     while (again);
1818
1819 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1820     tcsetattr(0,TCSANOW,&oter);
1821 #endif
1822
1823     std::cout << "Good bye !" << std::endl;
1824
1825     bbtkDebugDecTab("Interpreter",9);
1826   }
1827
1828 //=======================================================================
1829 void Interpreter::Graph(const std::vector<std::string>& words)
1830 {
1831   std::string page;
1832     bool system_display = true;
1833
1834     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1835       system_display = false; 
1836  
1837     if (words.size()==1) 
1838     {
1839       page = mVirtualExecuter->ShowGraph(".","0","0","","","",system_display);
1840     }
1841     else if (words.size()==2) 
1842     {
1843       page = mVirtualExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1844     }
1845     else if (words.size()==3) 
1846     {
1847       page = mVirtualExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1848     }
1849     else if (words.size()==4) 
1850     {
1851       page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1852     } 
1853     else if (words.size()==5) 
1854     {
1855       page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1856     } 
1857     else if (words.size()==6) 
1858     {
1859       page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1860     } 
1861     else if (words.size()==7) 
1862       {
1863         page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1864       } 
1865     
1866     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1867       mUser->InterpreterUserViewHtmlPage(page);
1868
1869   }
1870 //=======================================================================
1871
1872
1873 //=======================================================================
1874 void  Interpreter::Index(const std::string& filename, 
1875                          const std::string& type)
1876 {
1877   Factory::IndexEntryType t;
1878   if (type=="Initials") t = Factory::Initials;
1879   else if (type=="Categories") t = Factory::Categories;
1880   else if (type=="Packages") t = Factory::Packages;
1881   else if (type=="Adaptors") t = Factory::Adaptors;
1882   
1883   GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1884 }
1885 //=======================================================================
1886
1887
1888 //=======================================================================
1889 void  Interpreter::NewGUI(const std::string& boxname,
1890                              const std::string& instanceName)
1891 {
1892   if (mRealExecuter.expired())
1893     {
1894       bbtkError("command 'newgui' cannot be compiled yet");
1895     }
1896
1897   std::string typeName = instanceName+"Type";
1898   std::stringstream* s = new std::stringstream;
1899   // create the complex box
1900   (*s) << "define "<<typeName<<std::endl;
1901   //  (*s) << "  description 'Automatically generated user interface for the box "
1902   //       << boxname << "'" <<std::endl;
1903   // create the Layout box
1904   (*s) << "  load wx"<<std::endl;
1905   (*s) << "  new LayoutLine layout"<<std::endl;
1906   // create the output 'Widget'
1907   (*s) << "  output Widget layout.Widget Widget"<<std::endl;
1908   // the box change output 
1909   (*s) << "  new MultipleInputs change"<<std::endl;
1910   (*s) << "  output BoxChange change.Out BoxChange"<<std::endl;
1911
1912   // Browse the inputs of the box in order to find which ones are not 
1913   // connected and can be adapted from a widget adaptor
1914   // vector which stores the list of inputs of the box which must be connected
1915   std::vector<std::string> in;
1916  
1917   Factory::Pointer F = mVirtualExecuter->GetFactory();
1918   /*
1919   Package::Pointer user = F->GetPackage("user");
1920   */
1921   ComplexBlackBoxDescriptor::Pointer workspace = 
1922     mRealExecuter.lock()->GetCurrentDescriptor();
1923
1924   if (workspace==0)
1925     {
1926       delete s;
1927       bbtkError("Interpreter::CreateGUI : could not access the executer currently defined complex box");
1928     }
1929  
1930
1931   /*
1932     (ComplexBlackBoxDescriptor::Pointer)(user->GetBlackBoxMap().find("workspace")->second.get());
1933   */
1934
1935   BlackBox::Pointer box = workspace->GetPrototype()->bbGetBlackBox(boxname);
1936   //  BlackBox::InputConnectorMapType incm = box->bbGetInputConnectorMap();
1937   int nb = 0;
1938   BlackBox::InputConnectorMapType::iterator i;
1939   for (i=box->bbGetInputConnectorMap().begin();
1940        i!=box->bbGetInputConnectorMap().end();
1941        ++i)
1942     {
1943       // If the input is connected : continue
1944       if (i->second->IsConnected()) continue;
1945       // Get the input descriptor 
1946       const BlackBoxInputDescriptor* d = box->bbGetDescriptor()->GetInputDescriptor(i->first);
1947       // If it is a "system" input : skip it
1948       if ( ( d->GetCreatorTypeInfo() == typeid(AtomicBlackBoxDescriptor)) ||
1949            ( d->GetCreatorTypeInfo() == typeid(WxBlackBoxDescriptor)) )
1950         continue;
1951       bool widok = true;
1952       std::string widget,adaptor;
1953       // try to find a widget adaptor
1954       if (F->FindWidgetAdaptor(DataInfo(d->GetTypeInfo(),""),
1955                                d->GetDataInfo(),
1956                                adaptor))
1957         {
1958           // command to create the adaptor
1959           (*s) << "  new "<<adaptor<<" "<<i->first<<std::endl;
1960           // Sets the label of the widget adaptor to the name of the input
1961           (*s) << "  set "<<i->first<<".Label "<<i->first<<std::endl;
1962           // Sets the initial value of the widget to the value of the input
1963           (*s) << "  set "<<i->first<<".In \" "
1964                <<box->bbGetInputAsString(i->first)<<"\""
1965                << std::endl;
1966           // store the input name
1967           in.push_back(i->first);
1968           (*s) << "  connect "<<i->first<<".Widget layout.Widget"<<in.size()<<std::endl;
1969             //<i->first<<"'"<<std::endl;
1970           (*s) << "  connect "<<i->first<<".BoxChange change.In"<<in.size()<<std::endl;
1971         }
1972       // try to find a two pieces adaptor
1973       else if (F->FindWidgetAdaptor2(DataInfo(d->GetTypeInfo(),""),
1974                                      d->GetDataInfo(),
1975                                      widget,adaptor) )
1976         {
1977           // command to create the widget
1978           (*s) << "  new "<<widget<<" "<<i->first<<"Widget"<<std::endl;
1979           // command to create the adaptor
1980           (*s) << "  new "<<adaptor<<" "<<i->first<<std::endl;
1981           // connect the two
1982           (*s) << "  connect "<<i->first<<"Widget.Out "
1983                <<i->first<<".In"<<std::endl;
1984           // Sets the label of the widget adaptor to the name of the input
1985           (*s) << "  set "<<i->first<<"Widget.Label "<<i->first<<std::endl;
1986           // Sets the initial value of the widget to the value of the input
1987           (*s) << "  set "<<i->first<<"Widget.In \" "
1988                <<box->bbGetInputAsString(i->first)<<"\""<< std::endl;
1989           // store the input name
1990           in.push_back(i->first);
1991           (*s) << "  connect "<<i->first<<"Widget.Widget layout.Widget"<<in.size()<<std::endl;
1992             //<i->first<<"'"<<std::endl;
1993           (*s) << "  connect "<<i->first<<"Widget.BoxChange change.In"<<in.size()<<std::endl;
1994
1995         }
1996       // try to find an adaptor from string 
1997       // If found then can create a text input which 
1998       // will be automatically adapted 
1999       else if (F->FindAdaptor(DataInfo(typeid(std::string),""),
2000                                d->GetDataInfo(),
2001                                adaptor))
2002         {
2003           // command to create the adaptor
2004           (*s) << "  new InputText "<<i->first<<std::endl;
2005           // Sets the label of the widget adaptor to the name of the input
2006           (*s) << "  set "<<i->first<<".Title "<<i->first<<std::endl;
2007           // Sets the initial value of the widget to the value of the input
2008           (*s) << "  set "<<i->first<<".In \" "
2009                <<box->bbGetInputAsString(i->first)<<"\""<< std::endl;
2010           // store the input name
2011           in.push_back(i->first);
2012           (*s) << "  connect "<<i->first<<".Widget layout.Widget"<<in.size()<<std::endl;
2013             //<i->first<<"'"<<std::endl;
2014           (*s) << "  connect "<<i->first<<".BoxChange change.In"<<in.size()<<std::endl;
2015
2016         }
2017       else 
2018         {
2019           widok = false;
2020         }
2021       if (widok)
2022         {
2023           // command to create the output
2024           (*s) << "  output "<<i->first<<" "
2025                <<i->first<<".Out "<<i->first<<std::endl;
2026             //         <<" Output of the widget which allows to set "
2027           
2028         }
2029     }   
2030   // Inputs for window properties
2031   (*s) << "  input WinTitle layout.WinTitle Title"<<std::endl;
2032   (*s) << "  input WinWidth layout.WinWidth Width"<<std::endl;
2033   (*s) << "  input WinHeight layout.WinHeight Height"<<std::endl;
2034   (*s) << "  input WinDialog layout.WinDialog Dialog"<<std::endl;
2035   (*s) << "  input WinHide layout.WinHide Hide"<<std::endl;
2036
2037   
2038   
2039   // Execute the box executes the layout
2040   (*s) << "  exec layout" << std::endl;
2041   (*s) << "endefine" << std::endl;
2042   // (*s) << "help "<< typeName<< std::endl;
2043   // instanciate the box and connect it
2044   (*s) << "new "<<typeName<<" "<<instanceName<<std::endl;
2045   // connections
2046   std::vector<std::string>::iterator j;
2047   for (j=in.begin();j!=in.end();++j)
2048     {
2049       // connect
2050       (*s) << "connect "<<instanceName<<"."<<*j<<" "
2051            << boxname<<"."<<*j<<std::endl;
2052     }
2053   // That's all folks ! now execute the commands :
2054   SwitchToStream(s);
2055 }
2056 //=======================================================================
2057
2058
2059
2060  //==========================================================================
2061   void Interpreter::Debug(const std::string& name)
2062   {
2063     if ((name.length()==2)&&(name[0]=='-'))
2064       {
2065         if (name[1]=='D')
2066           {
2067             bbtk::StaticInitTime::PrintObjectListInfo = true;
2068           }
2069         if (name[1]=='C')
2070           {
2071             //      int o = MessageManager::GetMessageLevel("debug");
2072             //      if (o<2) MessageManager::SetMessageLevel("debug",2);
2073             mVirtualExecuter->GetFactory()->CheckPackages();
2074             //      MessageManager::SetMessageLevel("debug",o);
2075           }
2076       }
2077     else 
2078       {
2079         Object:: PrintObjectListInfo(name);
2080       }
2081   }
2082  //==========================================================================
2083  //==========================================================================
2084   std::string Interpreter::GetObjectName() const
2085   {
2086     return std::string("Interpreter");
2087   }
2088   //==========================================================================
2089   
2090   //==========================================================================
2091   std::string  Interpreter::GetObjectInfo() const 
2092   {
2093     std::stringstream i;
2094     return i.str();
2095   }
2096   //==========================================================================
2097
2098   //==========================================================================
2099 size_t  Interpreter::GetObjectSize() const 
2100 {
2101   size_t s = Superclass::GetObjectSize();
2102   s += Interpreter::GetObjectInternalSize();
2103   return s;
2104   }
2105   //==========================================================================
2106   //==========================================================================
2107 size_t  Interpreter::GetObjectInternalSize() const 
2108 {
2109   size_t s = sizeof(Interpreter);
2110   return s;
2111   }
2112   //==========================================================================
2113   //==========================================================================
2114   size_t  Interpreter::GetObjectRecursiveSize() const 
2115   {
2116     size_t s = Superclass::GetObjectRecursiveSize();
2117     s += Interpreter::GetObjectInternalSize();
2118     s += mVirtualExecuter->GetObjectRecursiveSize();
2119     return s;
2120   }
2121   //==========================================================================
2122 }//namespace
2123
2124