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