]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
*** empty log message ***
[bbtk.git] / kernel / src / bbtkInterpreter.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkInterpreter.cxx,v $ $
5   Language:  C++
6   Date:      $Date: 2008/10/02 12:29:26 $
7   Version:   $Revision: 1.72 $
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' | 'freeze_no_error' >";
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. 'freeze_no_error' is like freeze but also skips any error.";
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' allows 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.GetErrorMessage()<<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           try
535             {
536               InterpretLine(str, insideComment);
537             }
538           CATCH_MACRO;
539           
540        }//while
541        CloseCurrentFile();
542       }
543     }
544     CATCH_MACRO;
545     
546     CloseAllFiles();
547     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
548     bbtkDecTab("Interpreter",9);
549
550     mCommandLine = exm;
551     
552     return status;
553   }
554   //=======================================================================
555
556
557   //=======================================================================
558   /**
559    *  
560    */
561   Interpreter::ExitStatus 
562   Interpreter::InterpretBuffer( std::stringstream* buffer )
563   {
564     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
565
566     bool exm = mCommandLine;
567     mCommandLine = false;
568
569     ExitStatus status = Interpreter_OK;
570
571     try 
572     {
573       SwitchToStream(buffer);
574       bool insideComment = false; // for multiline comment
575       while (mFile.size()>0) 
576       {
577         while (!mFile.back()->eof()) {
578           mLine.back()++;
579           char buf[500];
580           mFile.back()->getline(buf,500);
581           std::string str(buf);
582           
583           int size=str.length();
584           if ( str[ size-1 ]==13  )
585             {
586               str.erase(size-1,1);
587             }
588           try
589             {
590               InterpretLine(str, insideComment);
591             }
592           CATCH_MACRO;
593         }//while
594         CloseCurrentFile();
595       }
596     }
597     CATCH_MACRO;
598     
599     CloseAllFiles();
600     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
601     bbtkDecTab("Interpreter",9);
602     
603     mCommandLine = exm;
604     return status;
605   }
606   //=======================================================================
607
608   //=======================================================================
609   /// Runs the interpretation of a command
610   Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
611   {
612     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
613
614     ExitStatus status = Interpreter_OK;
615
616     try 
617     {
618       bool insideComment = false;
619       InterpretLine(line, insideComment);
620     }
621     CATCH_MACRO;
622   
623
624     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
625                      <<std::endl);
626     bbtkDecTab("Interpreter",9);
627     
628     return status;
629   }
630   
631
632   //=======================================================================  
633   /**
634    *
635    */
636 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
637 {
638     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
639     bbtkMessage("echo",2,line<<std::endl);
640
641     std::vector<std::string> words;
642     SplitLine(line,words);
643
644     // Empty line
645     if (words.size()<1) 
646     {
647        bbtkDebugDecTab("Interpreter",9);
648        return;
649     }
650
651     // Single line comment : # or //
652     if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') ) 
653     {  
654        bbtkDebugDecTab("Interpreter",9);
655        bbtkMessage("Interpreter",9,"Comment"<<std::endl);
656        return;
657     }
658
659     // Multi line comment ( /* ... */ ) -delimiters on different lines !-
660     
661     if (words[0][0]=='/' && words[0][1]=='*') 
662     {  
663        bbtkDebugDecTab("Interpreter",9);
664        bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
665        insideComment = true;
666        return;
667     }
668
669     if (words[0][0]=='*' && words[0][1]=='/') 
670     {  
671        bbtkDebugDecTab("Interpreter",9);
672        bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
673        if ( !insideComment ) {
674           bbtkDebugDecTab("Interpreter",9);
675           bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);       
676        }
677        insideComment = false;
678        return;
679     }
680
681     if (insideComment) 
682     {  
683        bbtkDebugDecTab("Interpreter",9);
684        bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
685        return;
686     }
687
688     // Command 
689     CommandInfoType command;
690     InterpretCommand(words,command);
691
692     bbtkDebugMessage("Interpreter",9,
693                      "Command='"<<command.keyword
694                       <<"' code="<<command.code<<std::endl); 
695     int level=0;
696     std::string left,right,left2,right2;
697     std::string filename;
698     switch (command.code) 
699     {
700       case cNew :
701         mVirtualExecuter->Create(words[1],words[2]);
702         break;
703
704       case cDelete :
705         mVirtualExecuter->Destroy(words[1]);
706         break;
707
708       case cConnect :
709         Utilities::SplitAroundFirstDot(words[1],left,right);
710         Utilities::SplitAroundFirstDot(words[2],left2,right2);      
711         mVirtualExecuter->Connect(left,right,left2,right2);
712         break;
713
714       case cPackage :
715         mVirtualExecuter->BeginPackage(words[1]);
716         break;
717
718       case cEndPackage :
719         mVirtualExecuter->EndPackage();
720         break;
721
722       case cDefine :
723         if (mFileName.size()>0) 
724         {
725           filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
726         }
727         if (words.size()==2) 
728         {
729            mVirtualExecuter->Define(words[1],"",filename);
730         }
731         else
732         {
733            mVirtualExecuter->Define(words[1],words[2],filename);
734         }
735         break;
736
737       case cEndDefine :
738         mVirtualExecuter->EndDefine();
739         break;
740
741       case cKind :
742         mVirtualExecuter->Kind(words[1]);
743         break;
744
745       case cPrint :
746         mVirtualExecuter->Print(words[1]);
747         break;
748         
749       case cExec :
750         if (words[1]=="freeze") 
751           {
752             mVirtualExecuter->SetNoExecMode(true);
753             mThrow = false;
754           }
755         else if (words[1]=="freeze_no_error ") 
756           {
757             mVirtualExecuter->SetNoExecMode(true);
758             mVirtualExecuter->SetNoErrorMode(true);
759             mThrow = false;
760           }
761         else if (words[1]=="unfreeze") 
762           {
763             mVirtualExecuter->SetNoExecMode(false);
764             mVirtualExecuter->SetNoErrorMode(false);
765           }
766         else
767           {
768             mVirtualExecuter->Execute(words[1]);
769           }
770         break;
771
772       case cInput :
773         Utilities::SplitAroundFirstDot(words[2],left,right);
774         mVirtualExecuter->DefineInput(words[1],left,right,words[3]);
775         break;
776
777       case cOutput :
778         Utilities::SplitAroundFirstDot(words[2],left,right);
779         mVirtualExecuter->DefineOutput(words[1],left,right,words[3]);
780         break;
781
782       case cSet :
783         Utilities::SplitAroundFirstDot(words[1],left,right);
784         mVirtualExecuter->Set(left,right,words[2]);
785         break;
786
787       case cAuthor :
788         mVirtualExecuter->Author(words[1]);
789         break;
790
791       case cNewGUI :
792         NewGUI(words[1],words[2]);
793         break;
794
795       case cCategory :
796         mVirtualExecuter->Category(words[1]);
797         break;
798
799       case cIndex :
800         if (words.size()==1)
801              Index("tmp_index.html");
802         else if (words.size()==2)
803              Index(words[1]);
804         else if (words.size()==3)
805              Index(words[1],words[2]);
806         break;
807
808       case cDescription :
809         mVirtualExecuter->Description(words[1]);
810         break;
811
812       case cHelp :
813         Help(words);
814         break;
815
816       case cMessage : 
817         if (words.size()<3)
818         {
819           mVirtualExecuter->HelpMessages();
820         }
821         else
822         {
823           sscanf(words[2].c_str(),"%d",&level);
824           mVirtualExecuter->SetMessageLevel(words[1],level);
825         }
826         break;
827
828       case cGraph :
829         Graph(words);
830         break;
831
832       case cConfig :
833         Config();
834         break;
835
836       case cReset :  
837         Reset();
838         break;
839
840       case cInclude :
841         if (mCommandLine)
842         {
843            InterpretFile(words[1]); 
844         }
845         else
846         {
847             SwitchToFile(words[1]);
848         }
849         // if 'source' was given
850         if (words.size()==3) 
851           {
852             GetExecuter()->SetCurrentFileName(words[1]);
853           }
854         break;
855
856       case cLoad:
857         GetExecuter()->LoadPackage(words[1]);
858         break;
859
860       case cUnload:
861         GetExecuter()->UnLoadPackage(words[1]);
862         break;
863
864       case cQuit :
865         throw QuitException();
866         break;
867
868       case cDebug :
869         if (words.size()==2) Debug(words[1]);
870         else Debug("");
871         break;
872         /* obsolete
873       case cWorkspace :
874         if (words.size() == 2) 
875         {
876            if (words[1]=="freeze")        mVirtualExecuter->SetNoExecMode(true);
877            else if (words[1]=="unfreeze") mVirtualExecuter->SetNoExecMode(false);
878         }
879         else
880         {
881            mVirtualExecuter->SetWorkspaceName(words[2]);
882         }
883         break;
884         */
885       default:
886         bbtkInternalError("should not reach here !!!");
887    }
888
889    bbtkDecTab("Interpreter",9);
890 }
891   //=======================================================================  
892
893
894
895
896
897   //=======================================================================
898   /**
899    *
900    */
901 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
902 {
903     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
904
905     std::string delimiters = "\"";
906     std::vector<std::string> quote;
907     Utilities::SplitString(str,delimiters,quote);
908
909     delimiters = " \t";
910     std::vector<std::string>::iterator i;
911     for (i=quote.begin(); i!=quote.end(); ) 
912     {
913        Utilities::SplitString(*i,delimiters,tokens);
914        ++i;
915        if (i!=quote.end()) 
916        {
917         //    bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
918           tokens.push_back(*i);
919           ++i;
920        }
921     }
922
923     for (i=tokens.begin(); i!=tokens.end(); ++i) 
924     {
925        bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
926     }
927     bbtkDebugMessageCont("Interpreter",9,std::endl);
928
929     bbtkDebugDecTab("Interpreter",9);
930  }
931   //=======================================================================
932
933
934   //=======================================================================
935   void Interpreter::Reset()
936   {
937     // Cannot close all files if the reset command is read from a file !
938     //    CloseAllFiles();
939     mFileNameHistory.clear();
940     this->mVirtualExecuter->Reset();
941   }
942   //=======================================================================
943
944   //=======================================================================
945   /**
946    *
947    */
948   /*
949   void Interpreter::Print( const std::string& str)
950   {
951     if (mVirtualExecuter->GetNoExecMode()) return;
952
953     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
954
955  // TO DO :
956  // InterpretLine ("load std")
957  // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande 
958  // InterpretLine("new Print _P_") 
959  // InterpretLine("connect _C_.Out _P_.In")
960  // int num = 1
961  
962
963     std::vector<std::string> chains;
964     std::string delimiters("$");
965
966     // Skip delimiters at beginning.
967     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
968     bool is_text = true;
969     if (lastPos>0) is_text = false;
970
971     // Find first delimiter.
972     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
973
974     while (std::string::npos != pos || std::string::npos != lastPos)
975     {
976        if (is_text) 
977        {
978           // Found a text token, add it to the vector.
979           chains.push_back(str.substr(lastPos, pos - lastPos));
980  // std::string token = str.substr(lastPos, pos - lastPos)
981  // InterpretLine("set _C_.In%num% %token%")
982  
983        }
984        else 
985        {
986
987        // is an output (between $$) : decode 
988          std::string tok,box,output;
989          tok = str.substr(lastPos, pos - lastPos);
990          Utilities::SplitAroundFirstDot(tok,box,output);
991          chains.push_back( mVirtualExecuter->Get(box,output) );
992
993 // InterpretLine("connect %tok% _C_.In%num%") 
994
995        }
996         // Skip delimiters.  Note the "not_of"
997        lastPos = str.find_first_not_of(delimiters, pos);
998         // Find next delimiter
999        pos = str.find_first_of(delimiters, lastPos);
1000     //
1001        is_text = !is_text;
1002 // num ++;
1003      }
1004 // InterpretLine("exec _P_")
1005 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
1006
1007      std::vector<std::string>::iterator i;
1008      for (i= chains.begin(); i!=chains.end(); ++i) 
1009      {
1010
1011        Utilities::SubsBackslashN(*i);
1012        std::cout << *i;
1013      }
1014      std::cout << std::endl;
1015      bbtkDebugDecTab("Interpreter",9);
1016  }
1017 */
1018
1019   //=======================================================================
1020   /**
1021    *
1022    */
1023
1024   // =========================================================================
1025   void Interpreter::SwitchToFile( const std::string& name )
1026   {
1027   // Note : in the following :
1028   // name : the user supplied name 
1029   //      - abreviated name    e.g.       scr   scr.bbs
1030   //      - relative full name e.g.       ./scr.bbs   ../../scr.bbs 
1031   //      - absolute full name e.g.       /home/usrname/proj/dir/scr.bbs
1032   //          same for Windows, with      c:, d: ...
1033   //
1034   // use ./directory/subdir/scrname.bbs
1035   //
1036
1037     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
1038                          <<name<<"\")"<<std::endl);
1039
1040     std::vector<std::string> script_paths;
1041     std::string fullPathScriptName;  // full path script name
1042     std::string pkgname;             // e.g. <scriptname>.bbs
1043     std::vector<std::string> Filenames;
1044
1045     // The following is *NOT* a debug time message :
1046     // It's a user intended message.
1047     // Please don't remove it.
1048     bbtkMessage("Interpreter",1,
1049         "look for : [" << name
1050         << "]" << std::endl);
1051
1052
1053     std::string upath;
1054     pkgname = Utilities::ExtractScriptName(name,upath);
1055
1056     bbtkMessage("Interpreter",3,
1057                 "extract : pkgname [" << pkgname
1058                  << "] upath [" << upath << "]" << std::endl);
1059     bool fullnameGiven = false; 
1060     bool foundFile     = false;
1061
1062     // ==== "*" provided : load all scripts in given path 
1063     // relative (e.g. std/boxes/*) or absolute 
1064     if (pkgname == "*") 
1065       {
1066         int nbBssFiles;
1067         
1068         std::stringstream* stream = new std::stringstream;
1069         //if (upath.size()!=0) // avoid troubles for "*"
1070         
1071         // ==== no path provided : look in root bbs path
1072         if (upath.size()==0)
1073           {
1074             //      bbtkMessage("Interpreter",1,
1075             script_paths.push_back(  ConfigurationFile::GetInstance().Get_root_bbs_path() );
1076           }
1077         // ==== absolute path provided 
1078         else if (upath[0]=='/' || upath[1] == ':' ) 
1079           {
1080             if ( Utilities::IsDirectory( upath ) )
1081               {
1082                 script_paths.push_back(upath);
1083               }
1084             else 
1085               {
1086                 bbtkError("'"<<upath<<"' : directory does not exist"); 
1087               }
1088           }
1089         // ==== relative path provided : search all bbs path appended with 
1090         // the relative path provided
1091         else
1092           {    
1093              std::vector<std::string>::const_iterator i;
1094              for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1095                   i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1096                   i++)
1097                {
1098                  std::string full_path(*i);
1099                  // we *really* want '.' to be the current working directory
1100                  if (full_path == ".") {
1101                    char buf[2048]; // for getcwd
1102                    char * currentDir = getcwd(buf, 2048);
1103                    std::string cwd(currentDir);
1104                    full_path = currentDir;
1105                  } // if full_path
1106             
1107                  full_path += ConfigurationFile::GetInstance().Get_file_separator();
1108                  full_path += upath;
1109
1110                  if ( Utilities::IsDirectory( full_path ) )
1111                    {
1112                      script_paths.push_back(full_path);
1113                    }
1114                } 
1115              if (script_paths.empty())
1116                {
1117                  bbtkError("no '"<<upath<<"' subdir found in search paths" 
1118                            << std::endl);
1119                }
1120
1121           }
1122         // === search paths list complete : now explore it
1123
1124
1125         std::vector<std::string>::iterator i;
1126         for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1127           {
1128             bbtkMessage("Interpreter",1,
1129                         "--> Looking in '" << *i << "'" << std::endl);
1130          
1131             
1132             Filenames.clear();
1133             //int nbFiles = 
1134             Utilities::Explore(*i, false, Filenames);
1135             
1136             nbBssFiles = 0;
1137             for (std::vector<std::string>::iterator j = Filenames.begin(); 
1138                  j!= Filenames.end(); ++j)
1139               {
1140                 int lgr = (*j).size();
1141                 if (lgr < 5)
1142                   continue;  // ignore non .bbs file
1143                 if ((*j).substr(lgr-4, 4) != ".bbs")
1144                   continue;
1145                 
1146                 (*stream) << "include \"" << *j << "\"\n";
1147                 bbtkMessage("Interpreter",2,
1148                             "  --> Found '" << *j << "'" << std::endl);
1149                 
1150                 nbBssFiles++;
1151               } // for vector
1152             
1153             if (nbBssFiles==0)
1154               {
1155                 bbtkMessage("Interpreter",1,
1156                             "  --> No .bbs found"<< std::endl);
1157               } 
1158             else 
1159               {
1160                 bbtkMessage("Interpreter",1,
1161                             "  --> "<<nbBssFiles<<" .bbs found"<< std::endl);
1162                 SwitchToStream(stream);
1163               }
1164             
1165             //break; // a directory was found; we stop iterating
1166             // LG : No! We want all files included !
1167           } // for vector
1168         return;
1169       }  
1170     //=============== end pkgname=="*" ===========
1171
1172
1173     // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1174     // (not only a plain script name)
1175     // we trust him, and try to expland the directory name
1176     // WARNING : starting from current local directory :  ./whatYouWant  (./ mandatory!)
1177
1178     if (name[0]=='/' || name[1] == ':' || name[0]=='.')  // absolute path (linux/windows) or relative path
1179     { 
1180
1181       // ===========================================================check user supplied location
1182       fullnameGiven = true;
1183
1184       fullPathScriptName =  Utilities::ExpandLibName(name, false);
1185
1186       // allow user to always forget ".bbs"
1187       int l = fullPathScriptName.size();
1188
1189       if (l!=0) {
1190
1191       if (l>4)
1192       {
1193          if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1194          {
1195             fullPathScriptName = fullPathScriptName + ".bbs";
1196          }
1197       }
1198       else
1199       {
1200          fullPathScriptName = fullPathScriptName + ".bbs";   
1201       }
1202
1203       if ( Utilities::FileExists(fullPathScriptName))
1204       {
1205         foundFile = true;
1206       }
1207     } // endif l != 0
1208   }
1209   else
1210     // =============================== iterate on the paths
1211     {
1212       script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1213       std::string path;
1214       std::vector<std::string>::iterator i;
1215       for (i=script_paths.begin();i!=script_paths.end();++i)
1216         {
1217           path = *i;
1218           // we *really* want '.' to be the current working directory
1219           if (path == ".") {
1220             char buf[2048]; // for getcwd
1221             char * currentDir = getcwd(buf, 2048);
1222             std::string cwd(currentDir);
1223             path = currentDir;
1224           }
1225           
1226           fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1227           
1228           // Check if library exists
1229           if ( ! Utilities::FileExists(fullPathScriptName) )
1230             {
1231               // The following is *NOT* a debug time message :
1232               // It's a user intended message.
1233               // Please don't remove it.
1234               bbtkMessage("Interpreter",2,
1235                           "   [" <<fullPathScriptName <<"] : doesn't exist" 
1236                           <<std::endl);
1237               continue;  // try next path
1238             }
1239           bbtkMessage("Interpreter",2,
1240                       "   [" <<fullPathScriptName 
1241                       <<"] : found" <<std::endl);
1242           foundFile = true;
1243           break; // a script was found; we stop iterating
1244
1245         } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1246     }
1247     
1248     if (!foundFile)
1249       {
1250         if (fullnameGiven)
1251           if(fullPathScriptName == "")
1252             bbtkError("Path ["<<upath<<"] doesn't exist");
1253           else
1254             bbtkError("Script ["<<fullPathScriptName<<"] not found");
1255         else
1256           bbtkError("No ["<<pkgname<<".bbs] script found");
1257         return;
1258       }
1259     else
1260       LoadScript(fullPathScriptName,name);
1261     
1262     return;
1263   }
1264   //=======================================================================
1265
1266
1267   //=======================================================================
1268 void Interpreter::SwitchToStream( std::stringstream* stream )
1269 {
1270     mFile.push_back(stream);
1271     std::ostringstream buffer_name;
1272     bufferNb++;
1273     buffer_name << "buffer_" ;
1274
1275     if (mFileName.size()>0 )
1276     {
1277        buffer_name << mFileName.back() << "_" << mLine.back();
1278     }
1279     mFileName.push_back(buffer_name.str());
1280     mIncludeFileName.push_back(buffer_name.str());
1281     mLine.push_back(0);
1282 }
1283   //=======================================================================
1284
1285   //=======================================================================
1286
1287   void Interpreter::LoadScript( std::string fullPathScriptName,
1288                                 std::string includeScriptName)
1289   {
1290      Utilities::replace( fullPathScriptName , 
1291                          INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1292    
1293      if (find(mFileNameHistory.begin(),
1294               mFileNameHistory.end(),
1295               fullPathScriptName)!=mFileNameHistory.end())
1296      {
1297         return;
1298      }
1299
1300     std::ifstream* s;
1301     s = new std::ifstream;
1302     s->open(fullPathScriptName.c_str());
1303     if (!s->good())
1304     {
1305         bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1306         return;
1307     }
1308
1309     bbtkMessage("Interpreter",1,"   -->[" << fullPathScriptName 
1310                 << "] found" << std::endl);
1311
1312     mFile.push_back(s);
1313     mFileName.push_back(fullPathScriptName);
1314     mFileNameHistory.push_back(fullPathScriptName);
1315     mIncludeFileName.push_back(includeScriptName);
1316     mLine.push_back(0);
1317
1318     return;
1319   }
1320
1321   //=======================================================================
1322   /**
1323    *  
1324    */
1325   void Interpreter::CloseCurrentFile()
1326   {
1327     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1328                       <<std::endl);
1329
1330     if (mFile.size()==0)
1331     {
1332       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1333       return;
1334     }
1335
1336     bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1337
1338     std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1339     if (file!=0) file->close();
1340
1341     delete mFile.back();
1342     mFile.pop_back();
1343     mFileName.pop_back();
1344     mIncludeFileName.pop_back();
1345     mLine.pop_back();
1346
1347     bbtkDebugMessage("Interpreter",9," Remains "
1348                      <<mFile.size()
1349                      <<" open"<<std::endl);
1350     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1351                      <<std::endl);
1352   }
1353   //=======================================================================
1354
1355  //=======================================================================
1356   /**
1357    *  
1358    */
1359   void Interpreter::CloseAllFiles()
1360   {
1361     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1362                       <<std::endl);
1363
1364     while (mFile.size() != 0) 
1365     {
1366        CloseCurrentFile();
1367     }
1368     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1369                       <<std::endl);
1370   }
1371   //=======================================================================
1372
1373
1374
1375   //=======================================================================
1376   /**
1377    *  
1378    */
1379   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1380                                       CommandInfoType& info )
1381   {
1382     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1383
1384     // searches the command keyword
1385     CommandDictType::iterator c;
1386     c = mCommandDict.find(words[0]);
1387     if ( c == mCommandDict.end() ) {
1388       bbtkError(words[0]<<" : unknown command");
1389     }
1390
1391     // tests the number of args 
1392     if ( ( ((int)words.size())-1 < c->second.argmin ) ||
1393          ( ((int)words.size())-1 > c->second.argmax ) )
1394     {
1395        HelpCommand(words[0]);
1396        bbtkError(words[0]<<" : wrong number of arguments");
1397     }
1398
1399     info = c->second;
1400     bbtkDecTab("Interpreter",9);
1401   }
1402   //=======================================================================
1403
1404
1405   //=======================================================================
1406   /// Displays help on all the commands
1407 void Interpreter::Help(const std::vector<std::string>& words)
1408 {
1409     unsigned int nbarg = words.size()-1;
1410
1411     if (nbarg==0) 
1412     {
1413        HelpCommands();
1414     }
1415     else if (nbarg==1) 
1416     {
1417       if (words[1]=="packages") 
1418       {
1419          GetExecuter()->GetFactory()->PrintPackages(true);
1420          return;
1421       }
1422       try 
1423       {
1424           HelpCommand(words[1]);
1425       }
1426       catch (bbtk::Exception e) 
1427       {
1428          try 
1429          {
1430             GetExecuter()->GetFactory()->HelpPackage(words[1]);
1431             if ( mUser != 0 )
1432               {
1433                 std::string url = 
1434                   ConfigurationFile::GetInstance().Get_doc_path();
1435                 url += "/bbdoc/" + words[1] + "/index.html";
1436                 if (Utilities::FileExists(url)) 
1437                   {
1438                     mUser->InterpreterUserViewHtmlPage(url);
1439                   }
1440               }
1441          }
1442          catch (bbtk::Exception f) 
1443          {
1444            try 
1445              {
1446                std::string package;
1447                GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1448                if ( mUser != 0 )
1449                  {
1450                    std::string url = 
1451                      ConfigurationFile::GetInstance().Get_doc_path();
1452                    url += "/bbdoc/" + package + "/index.html";
1453                    if (Utilities::FileExists(url)) 
1454                      {
1455                        url += "#" + words[1];
1456                        mUser->InterpreterUserViewHtmlPage(url);
1457                      }
1458                  }
1459              }
1460            catch (bbtk::Exception g) 
1461              {
1462                try
1463                  {
1464                    GetExecuter()->ShowRelations(words[1],"0","9999");
1465                  }
1466                catch (bbtk::Exception h){
1467                  bbtkError("\""<<words[1].c_str()
1468                            <<"\" is not a known command, package, black box type or black box name");
1469                }
1470              }
1471          }
1472       }
1473     }
1474     else if (nbarg==2) 
1475     {
1476       if (words[2]=="all")
1477       {
1478          if ( words[1]=="packages" )
1479          {
1480             GetExecuter()->GetFactory()->PrintPackages(true,true);
1481             return;
1482           }
1483          try 
1484          {
1485             GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1486          }
1487          catch (bbtk::Exception f) 
1488          {
1489          }
1490      }
1491      else 
1492      {
1493         HelpCommand(words[0]);
1494         bbtkError(words[0]<<" : syntax error");
1495      }
1496   }
1497   else 
1498   {
1499      bbtkError("Should not reach here !!!");
1500   }
1501 }
1502   //=======================================================================
1503
1504    //===================================================================    
1505   /// Displays the Configuration
1506   void Interpreter::Config() const
1507   {
1508     ConfigurationFile::GetInstance().GetHelp(1);
1509   }  
1510    //===================================================================    
1511
1512   //=======================================================================
1513   /// Displays help on all the commands
1514   void Interpreter::HelpCommands()
1515   {
1516     std::cout << "Available commands :" << std::endl;
1517     CommandDictType::iterator i;
1518     for ( i =  mCommandDict.begin();
1519           i != mCommandDict.end();
1520         ++i) {
1521               std::cout << " " << i->first << std::endl;
1522       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1523       //     std::cout << "    " << i->second.help << std::endl;
1524
1525     }
1526   }
1527   //=======================================================================
1528
1529
1530   //=======================================================================
1531   /// Displays help on a particular commands
1532   void Interpreter::HelpCommand(const std::string& s)
1533   {
1534     CommandDictType::iterator c;
1535     c = mCommandDict.find(s);
1536     if ( c == mCommandDict.end() ) {
1537       bbtkError(s<<" : Unknown command");
1538     }   
1539     //    std::cout << " " << s << " : "<<  std::endl;
1540     //    CommandParamDictType::iterator i;
1541     //    for ( i =  c->second.begin();
1542     //      i != c->second.end();
1543     //      ++i) {
1544     std::cout << " usage : " << c->second.syntax << std::endl;
1545     std::cout << "  " << c->second.help << std::endl;
1546
1547   }
1548   //=======================================================================
1549
1550
1551   //=======================================================================
1552   /// Fills the vector commands with the commands which 
1553   /// have the first n chars of buf for prefix
1554   /// TODO : skip initial spaces in buf and also return the position of first
1555   /// non blank char in buf
1556   void Interpreter::FindCommandsWithPrefix( char* buf,
1557                                             int n,
1558                                             std::vector<std::string>& commands )
1559   {
1560     CommandDictType::const_iterator i;
1561     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1562     {
1563       if ((i->first).find(buf,0,n) == 0) 
1564         commands.push_back(i->first);
1565     }
1566   }
1567   //=======================================================================
1568
1569
1570
1571   //=======================================================================
1572 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1573   
1574   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1575   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1576   
1577   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1578   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1579   // E.G. STORE THIS IN bbtk_config.xml
1580 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1581 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1582 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1583 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1584 #define BBTK_BACKSPACE_KBCODE   0x00000008
1585 #define BBTK_DEL_KBCODE         0x0000007F
1586 #define BBTK_SPACE_KBCODE       0x00000020 
1587
1588   //=======================================================================
1589   void Interpreter::GetLineFromPrompt(std::string& s)
1590   {
1591     int c;
1592     unsigned int ind=0;
1593
1594     unsigned int MAX_LINE_SIZE = 160;
1595     unsigned int MAX_HISTORY_SIZE = 100;
1596
1597     char* newline = new char[MAX_LINE_SIZE];
1598     memset(newline,0,MAX_LINE_SIZE);
1599     char* histline = new char[MAX_LINE_SIZE];
1600     memset(histline,0,MAX_LINE_SIZE);
1601
1602     char* line = newline;
1603     unsigned int hist = mHistory.size();
1604
1605     write(1,"> ",2);
1606     while(1)
1607     {
1608        c=0;
1609        read ( STDIN_FILENO, &c, 4) ;
1610
1611        bbtkDebugMessage("debug",9,"[0x"<<std::hex<<c<<"]\n");
1612
1613        // Printable character
1614        if ( (ind<MAX_LINE_SIZE-1) &&
1615             ( c >= BBTK_SPACE_KBCODE ) && 
1616             ( c <  BBTK_DEL_KBCODE )) 
1617        {
1618           PrintChar(c);
1619           line[ind++]=c;
1620        }
1621       // CR
1622        else if (c=='\n')
1623        {
1624        // delete the unused line
1625           if (line==newline)
1626               delete histline;
1627           else
1628               delete newline;
1629    
1630     // empty lines are not stored in from history
1631           if (strlen(line)) 
1632           {
1633              // if history too long : delete oldest command
1634              if (mHistory.size()>MAX_HISTORY_SIZE) 
1635              {
1636                 delete mHistory.front();
1637                 mHistory.pop_front();
1638              }
1639              mHistory.push_back(line);
1640           }
1641           break;
1642         }
1643        // Backspace
1644         else if ( (ind>0) && 
1645                   ((c == BBTK_BACKSPACE_KBCODE) ||
1646                    (c == BBTK_DEL_KBCODE)) )
1647           {
1648             line[ind--]=' ';
1649             BackSpace();
1650           }
1651         // Tab 
1652         else if (c=='\t')
1653           {
1654             // TODO : Command completion  
1655             std::vector<std::string> commands;
1656             FindCommandsWithPrefix( line,ind,commands);
1657             if (commands.size()==1) 
1658               {
1659                 std::string com = *commands.begin();
1660                 for (; ind<com.size(); ++ind) 
1661                   {
1662                     PrintChar(com[ind]); 
1663                     line[ind]=com[ind];
1664                   }
1665                 PrintChar(' '); 
1666                 line[ind++]=' ';
1667               }
1668             else if (commands.size()>1) 
1669               {
1670                 std::vector<std::string>::iterator i;
1671                 write(1,"\n",1);
1672                 for (i=commands.begin();i!=commands.end();++i) 
1673                   {
1674                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1675                     PrintChar(' ');
1676                   }
1677                 write(STDOUT_FILENO,"\n> ",3);
1678                 //for (int j=0;j<ind;++j) 
1679                   //{
1680                     write(STDOUT_FILENO,line,ind); 
1681                     //  }
1682               }
1683           }
1684         // Arrow up : back in history
1685         else if (c==BBTK_UP_ARROW_KBCODE)
1686           {
1687             if (hist) 
1688               {
1689                 // erase current line
1690                 while (ind--) BackSpace();
1691                 // 
1692                 hist--;
1693                 // 
1694                 strcpy(histline,mHistory[hist]);
1695                 line = histline;
1696                 ind = strlen(line);
1697                 
1698                 write(STDOUT_FILENO,line,ind);
1699               }
1700           }
1701         // Arrow down : down in history
1702         else if (c==BBTK_DOWN_ARROW_KBCODE)
1703           {
1704             if (hist<mHistory.size()-1) 
1705               {
1706                 // erase current line
1707                 while (ind--) BackSpace();
1708                 // 
1709                 hist++;
1710                 // 
1711                 strcpy(histline,mHistory[hist]);
1712                 line = histline;
1713                 ind = strlen(line);
1714                 
1715                 write(STDOUT_FILENO,line,ind);
1716               }
1717             // end of history : switch back to newline
1718             else if (hist==mHistory.size()-1)
1719               {
1720                 // erase current line
1721                 while (ind--) BackSpace();
1722                 // 
1723                 hist++;
1724                 // 
1725                 line = newline;
1726                 ind = strlen(line);
1727                 
1728                 write(STDOUT_FILENO,line,ind);
1729               }
1730           }
1731         // Arrow right
1732         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1733           {
1734             PrintChar(line[ind]);
1735             ind++;
1736           }
1737
1738         // Arrow left
1739         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1740           {
1741             PrintChar('\b');
1742             ind--;
1743     
1744           }
1745
1746       }
1747     write(STDOUT_FILENO,"\n\r",2);
1748     
1749     
1750     s = line;
1751     
1752   }
1753 #else
1754
1755   //=======================================================================
1756   void Interpreter::GetLineFromPrompt(std::string& s)
1757   {  
1758     s.clear();
1759
1760     putchar('>');
1761     putchar(' ');
1762
1763     do 
1764     {
1765       char c = getchar();
1766       if (c=='\n') 
1767       {
1768         putchar('\n');
1769         break;
1770       }
1771       if (c=='\t') 
1772       {
1773         // putchar('T');
1774         continue;
1775       }
1776       // putchar(c);
1777       s += c;
1778     } 
1779     while (true);  
1780     
1781   }
1782   //=======================================================================  
1783
1784 #endif
1785
1786
1787
1788   //=======================================================================
1789   void Interpreter::CommandLineInterpreter()
1790   {
1791     bbtkDebugMessageInc("Interpreter",9,
1792                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1793
1794 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1795     // Initialise the tty in non canonical mode with no echo
1796     // oter remembers the previous settings to restore them after 
1797     struct termios ter,oter;
1798     tcgetattr(0,&ter);
1799     oter=ter;
1800     ter.c_lflag &= ~ECHO;
1801     ter.c_lflag &= ~ICANON;
1802     ter.c_cc[VMIN]=1;
1803     ter.c_cc[VTIME]=0;
1804     tcsetattr(0,TCSANOW,&ter);
1805 #endif
1806     
1807     mCommandLine = true;
1808     bool again = true;
1809     bool insideComment = false; // for multiline comment  
1810     do 
1811     {
1812       try
1813       {
1814         std::string line;
1815         GetLineFromPrompt(line);
1816         InterpretLine(line, insideComment);
1817       }
1818       catch (QuitException e)
1819       {
1820         bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1821         again = false;
1822       }
1823       catch (bbtk::Exception e) 
1824       {
1825         e.Print();
1826       }
1827         catch (std::exception& e) 
1828       {
1829         std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1830       }
1831       catch (...)
1832       {
1833         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1834       }
1835     }
1836     while (again);
1837
1838 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1839     tcsetattr(0,TCSANOW,&oter);
1840 #endif
1841
1842     std::cout << "Good bye !" << std::endl;
1843
1844     bbtkDebugDecTab("Interpreter",9);
1845   }
1846
1847 //=======================================================================
1848 void Interpreter::Graph(const std::vector<std::string>& words)
1849 {
1850   std::string page;
1851     bool system_display = true;
1852
1853     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1854       system_display = false; 
1855  
1856     if (words.size()==1) 
1857     {
1858       page = mVirtualExecuter->ShowGraph(".","0","0","","","",system_display);
1859     }
1860     else if (words.size()==2) 
1861     {
1862       page = mVirtualExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1863     }
1864     else if (words.size()==3) 
1865     {
1866       page = mVirtualExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1867     }
1868     else if (words.size()==4) 
1869     {
1870       page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1871     } 
1872     else if (words.size()==5) 
1873     {
1874       page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1875     } 
1876     else if (words.size()==6) 
1877     {
1878       page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1879     } 
1880     else if (words.size()==7) 
1881       {
1882         page = mVirtualExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1883       } 
1884     
1885     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1886       mUser->InterpreterUserViewHtmlPage(page);
1887
1888   }
1889 //=======================================================================
1890
1891
1892 //=======================================================================
1893 void  Interpreter::Index(const std::string& filename, 
1894                          const std::string& type)
1895 {
1896   Factory::IndexEntryType t;
1897   if (type=="Initials") t = Factory::Initials;
1898   else if (type=="Categories") t = Factory::Categories;
1899   else if (type=="Packages") t = Factory::Packages;
1900   else if (type=="Adaptors") t = Factory::Adaptors;
1901   
1902   GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1903 }
1904 //=======================================================================
1905
1906
1907 //=======================================================================
1908 void  Interpreter::NewGUI(const std::string& boxname,
1909                              const std::string& instanceName)
1910 {
1911   if (mRealExecuter.expired())
1912     {
1913       bbtkError("command 'newgui' cannot be compiled yet");
1914     }
1915
1916   std::string typeName = instanceName+"Type";
1917   std::stringstream* s = new std::stringstream;
1918   // create the complex box
1919   (*s) << "define "<<typeName<<std::endl;
1920   //  (*s) << "  description 'Automatically generated user interface for the box "
1921   //       << boxname << "'" <<std::endl;
1922   // create the Layout box
1923   (*s) << "  load wx"<<std::endl;
1924   (*s) << "  new LayoutLine layout"<<std::endl;
1925   // create the output 'Widget'
1926   (*s) << "  output Widget layout.Widget Widget"<<std::endl;
1927   // the box change output 
1928   (*s) << "  new MultipleInputs change"<<std::endl;
1929   (*s) << "  output BoxChange change.Out BoxChange"<<std::endl;
1930
1931   // Browse the inputs of the box in order to find which ones are not 
1932   // connected and can be adapted from a widget adaptor
1933   // vector which stores the list of inputs of the box which must be connected
1934   std::vector<std::string> in;
1935  
1936   Factory::Pointer F = mVirtualExecuter->GetFactory();
1937   /*
1938   Package::Pointer user = F->GetPackage("user");
1939   */
1940   ComplexBlackBoxDescriptor::Pointer workspace = 
1941     mRealExecuter.lock()->GetCurrentDescriptor();
1942
1943   if (workspace==0)
1944     {
1945       delete s;
1946       bbtkError("Interpreter::CreateGUI : could not access the executer currently defined complex box");
1947     }
1948  
1949
1950   /*
1951     (ComplexBlackBoxDescriptor::Pointer)(user->GetBlackBoxMap().find("workspace")->second.get());
1952   */
1953
1954   BlackBox::Pointer box = workspace->GetPrototype()->bbGetBlackBox(boxname);
1955   //  BlackBox::InputConnectorMapType incm = box->bbGetInputConnectorMap();
1956   // int nb = 0;
1957   BlackBox::InputConnectorMapType::iterator i;
1958   for (i=box->bbGetInputConnectorMap().begin();
1959        i!=box->bbGetInputConnectorMap().end();
1960        ++i)
1961     {
1962       // If the input is connected : continue
1963       if (i->second->IsConnected()) continue;
1964       // Get the input descriptor 
1965       const BlackBoxInputDescriptor* d = box->bbGetDescriptor()->GetInputDescriptor(i->first);
1966       // If it is a "system" input : skip it
1967       if ( ( d->GetCreatorTypeInfo() == typeid(AtomicBlackBoxDescriptor)) ||
1968            ( d->GetCreatorTypeInfo() == typeid(WxBlackBoxDescriptor)) )
1969         continue;
1970       bool widok = true;
1971       std::string widget,adaptor;
1972       // try to find a widget adaptor
1973       if (F->FindWidgetAdaptor(DataInfo(d->GetTypeInfo(),""),
1974                                d->GetDataInfo(),
1975                                adaptor))
1976         {
1977           // command to create the adaptor
1978           (*s) << "  new "<<adaptor<<" "<<i->first<<std::endl;
1979           // Sets the label of the widget adaptor to the name of the input
1980           (*s) << "  set "<<i->first<<".Label "<<i->first<<std::endl;
1981           // Sets the initial value of the widget to the value of the input
1982           (*s) << "  set "<<i->first<<".In \" "
1983                <<box->bbGetInputAsString(i->first)<<"\""
1984                << std::endl;
1985           // store the input name
1986           in.push_back(i->first);
1987           (*s) << "  connect "<<i->first<<".Widget layout.Widget"<<in.size()<<std::endl;
1988             //<i->first<<"'"<<std::endl;
1989           (*s) << "  connect "<<i->first<<".BoxChange change.In"<<in.size()<<std::endl;
1990         }
1991       // try to find a two pieces adaptor
1992       else if (F->FindWidgetAdaptor2(DataInfo(d->GetTypeInfo(),""),
1993                                      d->GetDataInfo(),
1994                                      widget,adaptor) )
1995         {
1996           // command to create the widget
1997           (*s) << "  new "<<widget<<" "<<i->first<<"Widget"<<std::endl;
1998           // command to create the adaptor
1999           (*s) << "  new "<<adaptor<<" "<<i->first<<std::endl;
2000           // connect the two
2001           (*s) << "  connect "<<i->first<<"Widget.Out "
2002                <<i->first<<".In"<<std::endl;
2003           // Sets the label of the widget adaptor to the name of the input
2004           (*s) << "  set "<<i->first<<"Widget.Label "<<i->first<<std::endl;
2005           // Sets the initial value of the widget to the value of the input
2006           (*s) << "  set "<<i->first<<"Widget.In \" "
2007                <<box->bbGetInputAsString(i->first)<<"\""<< std::endl;
2008           // store the input name
2009           in.push_back(i->first);
2010           (*s) << "  connect "<<i->first<<"Widget.Widget layout.Widget"<<in.size()<<std::endl;
2011             //<i->first<<"'"<<std::endl;
2012           (*s) << "  connect "<<i->first<<"Widget.BoxChange change.In"<<in.size()<<std::endl;
2013
2014         }
2015       // try to find an adaptor from string 
2016       // If found then can create a text input which 
2017       // will be automatically adapted 
2018       else if (F->FindAdaptor(DataInfo(typeid(std::string),""),
2019                                d->GetDataInfo(),
2020                                adaptor))
2021         {
2022           // command to create the adaptor
2023           (*s) << "  new InputText "<<i->first<<std::endl;
2024           // Sets the label of the widget adaptor to the name of the input
2025           (*s) << "  set "<<i->first<<".Title "<<i->first<<std::endl;
2026           // Sets the initial value of the widget to the value of the input
2027           (*s) << "  set "<<i->first<<".In \" "
2028                <<box->bbGetInputAsString(i->first)<<"\""<< std::endl;
2029           // store the input name
2030           in.push_back(i->first);
2031           (*s) << "  connect "<<i->first<<".Widget layout.Widget"<<in.size()<<std::endl;
2032             //<i->first<<"'"<<std::endl;
2033           (*s) << "  connect "<<i->first<<".BoxChange change.In"<<in.size()<<std::endl;
2034
2035         }
2036       else 
2037         {
2038           widok = false;
2039         }
2040       if (widok)
2041         {
2042           // command to create the output
2043           (*s) << "  output "<<i->first<<" "
2044                <<i->first<<".Out "<<i->first<<std::endl;
2045             //         <<" Output of the widget which allows to set "
2046           
2047         }
2048     }   
2049   // Inputs for window properties
2050   (*s) << "  input WinTitle layout.WinTitle Title"<<std::endl;
2051   (*s) << "  input WinWidth layout.WinWidth Width"<<std::endl;
2052   (*s) << "  input WinHeight layout.WinHeight Height"<<std::endl;
2053   (*s) << "  input WinDialog layout.WinDialog Dialog"<<std::endl;
2054   (*s) << "  input WinHide layout.WinHide Hide"<<std::endl;
2055
2056   
2057   
2058   // Execute the box executes the layout
2059   (*s) << "  exec layout" << std::endl;
2060   (*s) << "endefine" << std::endl;
2061   // (*s) << "help "<< typeName<< std::endl;
2062   // instanciate the box and connect it
2063   (*s) << "new "<<typeName<<" "<<instanceName<<std::endl;
2064   // connections
2065   std::vector<std::string>::iterator j;
2066   for (j=in.begin();j!=in.end();++j)
2067     {
2068       // connect
2069       (*s) << "connect "<<instanceName<<"."<<*j<<" "
2070            << boxname<<"."<<*j<<std::endl;
2071     }
2072   // That's all folks ! now execute the commands :
2073   SwitchToStream(s);
2074 }
2075 //=======================================================================
2076
2077
2078
2079  //==========================================================================
2080   void Interpreter::Debug(const std::string& name)
2081   {
2082     if ((name.length()==2)&&(name[0]=='-'))
2083       {
2084         if (name[1]=='D')
2085           {
2086             bbtk::StaticInitTime::PrintObjectListInfo = true;
2087           }
2088         if (name[1]=='C')
2089           {
2090             //      int o = MessageManager::GetMessageLevel("debug");
2091             //      if (o<2) MessageManager::SetMessageLevel("debug",2);
2092             mVirtualExecuter->GetFactory()->CheckPackages();
2093             //      MessageManager::SetMessageLevel("debug",o);
2094           }
2095       }
2096     else 
2097       {
2098         Object:: PrintObjectListInfo(name);
2099       }
2100   }
2101  //==========================================================================
2102  //==========================================================================
2103   std::string Interpreter::GetObjectName() const
2104   {
2105     return std::string("Interpreter");
2106   }
2107   //==========================================================================
2108   
2109   //==========================================================================
2110   std::string  Interpreter::GetObjectInfo() const 
2111   {
2112     std::stringstream i;
2113     return i.str();
2114   }
2115   //==========================================================================
2116
2117   //==========================================================================
2118 size_t  Interpreter::GetObjectSize() const 
2119 {
2120   size_t s = Superclass::GetObjectSize();
2121   s += Interpreter::GetObjectInternalSize();
2122   return s;
2123   }
2124   //==========================================================================
2125   //==========================================================================
2126 size_t  Interpreter::GetObjectInternalSize() const 
2127 {
2128   size_t s = sizeof(Interpreter);
2129   return s;
2130   }
2131   //==========================================================================
2132   //==========================================================================
2133   size_t  Interpreter::GetObjectRecursiveSize() const 
2134   {
2135     size_t s = Superclass::GetObjectRecursiveSize();
2136     s += Interpreter::GetObjectInternalSize();
2137     s += mVirtualExecuter->GetObjectRecursiveSize();
2138     return s;
2139   }
2140   //==========================================================================
2141 }//namespace
2142
2143