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