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