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