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