]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
Bug fix in Utilities::SplitAroundFirstDot
[bbtk.git] / kernel / src / bbtkInterpreter.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkInterpreter.cxx,v $ $
5   Language:  C++
6   Date:      $Date: 2008/01/23 07:51:51 $
7   Version:   $Revision: 1.3 $
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 "bbtkMessageManager.h"
25 #include "bbtkConfigurationFile.h"
26 #include "bbtkWxConsole.h"
27 #include "bbtkUtilities.h"
28 #include <sys/stat.h>
29 #ifdef CMAKE_HAVE_TERMIOS_H
30 #include <termios.h>
31 #define BBTK_USE_TERMIOS_BASED_PROMPT
32 #endif
33
34
35 namespace bbtk
36 {
37
38 Interpreter* Interpreter::mGlobalInterpreter = NULL;
39
40  //=======================================================================
41  /**
42    *  
43    */
44   Interpreter::Interpreter() 
45     :
46     mCommandLine(false), verbose(false)
47   {
48     bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
49     bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
50     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
51  
52     mGlobalInterpreter = this;
53
54     //    mFactory = new bbtk::Factory();
55     mExecuter = new bbtk::Executer();
56     //mExecuter->SetFactory(mFactory);
57
58     // Builds the commands dict
59     CommandInfoType info;
60    
61     info.keyword = "new";
62     info.argmin = 2;
63     info.argmax = 2;
64     info.code = cNew;
65     info.syntax = "new <type> <name>";
66     info.help = "Creates a new black box of type <type> with name <name>";
67     mCommandDict[info.keyword] = info;
68     
69     info.keyword = "delete";
70     info.argmin = 1;
71     info.argmax = 1;
72     info.code = cDelete;
73     info.syntax = "delete <box>";
74     info.help = "Deletes the black box of name <box>";
75     mCommandDict[info.keyword] = info;
76
77     info.keyword = "connect";
78     info.argmin = 2;
79     info.argmax = 2;
80     info.code = cConnect;
81     info.syntax = "connect <box1.output> <box2.input>";
82     info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
83     mCommandDict[info.keyword] = info;
84
85     info.keyword = "print";
86     info.argmin = 1;
87     info.argmax = 1;
88     info.code = cPrint;
89     info.syntax = "print <string>";
90     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').";
91     mCommandDict[info.keyword] = info;
92
93     info.keyword = "exec";
94     info.argmin = 1;
95     info.argmax = 2;
96     info.code = cExec;
97     info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
98     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.";
99     mCommandDict[info.keyword] = info;
100
101     info.keyword = "define";
102     info.argmin = 1;
103     info.argmax = 2;
104     info.code = cDefine;
105     info.syntax = "define <type> [<package>]";
106     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.";
107     mCommandDict[info.keyword] = info;
108     
109     info.keyword = "endefine";
110     info.argmin = 0;
111     info.argmax = 0;
112     info.code = cEndDefine;
113     info.syntax = "endefine";
114     info.help = "Ends the definition of a new type of complex black box";
115     mCommandDict[info.keyword] = info;
116
117     info.keyword = "input";
118     info.argmin = 3;
119     info.argmax = 3;
120     info.code = cInput;
121     info.syntax = "input <name> <box.input> <help>";
122     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";
123     mCommandDict[info.keyword] = info;
124
125     info.keyword = "output";
126     info.argmin = 3;
127     info.argmax = 3;
128     info.code = cOutput;
129     info.syntax = "output <name> <box.output> <help>";
130     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";
131     mCommandDict[info.keyword] = info;
132
133     info.keyword = "set";
134     info.argmin = 2;
135     info.argmax = 2;
136     info.code = cSet;
137     info.syntax = "set <box.input> <value>";
138     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";
139     mCommandDict[info.keyword] = info;
140    
141     info.keyword = "config";  // JPR
142     info.argmin = 0;
143     info.argmax = 1;
144     info.code = cConfig;
145     info.syntax = "config [<verbose>|<v>]";
146     info.help = "Prints the value of all configuration parameters";
147     mCommandDict[info.keyword] = info;
148
149     info.keyword = "reset";  //EED
150     info.argmin = 0;
151     info.argmax = 0;
152     info.code = cReset;
153     info.syntax = "reset";
154     info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
155     mCommandDict[info.keyword] = info;
156
157     info.keyword = "author";
158     info.argmin = 1;
159     info.argmax = 1;
160     info.code = cAuthor;
161     info.syntax = "author <string>";
162     info.help = "Adds the string <string> to the author information of the black box being defined";
163     mCommandDict[info.keyword] = info;
164
165     info.keyword = "description";
166     info.argmin = 1;
167     info.argmax = 1;
168     info.code = cDescription;
169     info.syntax = "description <string>";
170     info.help = "Adds the string <string> to the descriptive information of the black box being defined";
171     mCommandDict[info.keyword] = info;
172
173     info.keyword = "help";
174     info.argmin = 0;
175     info.argmax = 2;
176     info.code = cHelp;
177     info.syntax = "help";
178     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>";
179     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.";
180     mCommandDict[info.keyword] = info;
181
182     info.keyword = "message";
183     info.argmin = 0;
184     info.argmax = 2;
185     info.code = cMessage;
186     info.syntax = "message <category> <level>";
187     info.help = "Sets the level of the category of messages <category> to <level>.\n  If category='All' then sets the level for all categories. If no category nor level is passed then prints info on available categories of messages and their current level.";
188     mCommandDict[info.keyword] = info;
189
190     info.keyword = "include";
191     info.argmin = 1;
192     info.argmax = 1;
193     info.code = cInclude;
194     info.syntax = "include <filename>";
195     info.help = "Includes the file <filename>";
196     mCommandDict[info.keyword] = info;
197
198     info.keyword = "quit";
199     info.argmin = 0;
200     info.argmax = 0;
201     info.code = cQuit;
202     info.syntax = "quit";
203     info.help = "Quits the program (during script execution it stops the complete execution)";
204     mCommandDict[info.keyword] = info;
205
206     info.keyword = "load";
207     info.argmin = 1;
208     info.argmax = 1;
209     info.code = cLoad;
210     info.syntax = "load <packagename>";
211     info.help = "Loads the black box package <packagename>";
212     mCommandDict[info.keyword] = info;
213
214     info.keyword = "unload";
215     info.argmin = 1;
216     info.argmax = 1;
217     info.code = cUnload;
218     info.syntax = "unload <packagename>";
219     info.help = "Unloads the black box package <packagename>";
220     mCommandDict[info.keyword] = info;
221
222     info.keyword = "graph";
223     info.argmin = 0;
224     info.argmax = 6;
225     info.code = cGraph;
226     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 ]]]]]]";
227     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')";
228     mCommandDict[info.keyword] = info;
229
230     /*
231     info.keyword = "workspace";
232     info.argmin = 1;
233     info.argmax = 2;
234     info.code = cWorkspace;
235     info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
236     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.";
237     mCommandDict[info.keyword] = info;
238     */
239
240     bbtkDebugDecTab("Interpreter",9);
241
242   } 
243   //=======================================================================
244   
245   
246   
247   //=======================================================================  
248   /**
249    *  
250    */
251   Interpreter::~Interpreter()
252   {
253     bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
254     delete mExecuter;
255     //delete mFactory;
256
257     //    std::cout <<"EO Interpreter::~Interpreter()"<<std::endl;
258     bbtkDebugDecTab("Interpreter",9);
259   }
260   //=======================================================================
261
262
263   //=======================================================================
264   /**
265    *  
266    */
267   void Interpreter::InterpretFile( const std::string& filename,  bool use_configuration_file, bool verbose)
268   {
269     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
270
271     bool exm = mCommandLine;
272     mCommandLine = false;
273
274     try 
275     {
276       SwitchToFile(filename, use_configuration_file, verbose);
277       bool insideComment = false; // for multiline comment
278       while (mFile.size()>0) 
279       {
280          while ((mFile.size()>0) && 
281                 (!mFile.back()->eof()))
282          {
283             mLine.back()++;
284             char buf[500];
285             mFile.back()->getline(buf,500);
286       
287             std::string str(buf);
288             int size=str.length();
289             if ( str[ size-1 ]==13  )
290             {
291                str.erase(size-1,1);
292             }
293       
294             InterpretLine(str, insideComment);
295          }
296         //if (mFile.size()>0) 
297         CloseCurrentFile();
298       }
299     }
300     catch (QuitException e) 
301     {
302     }
303     catch (bbtk::Exception e) 
304     {
305       std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
306       if (mFileName.size()) {
307          std::cerr << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
308          std::cerr << "* LINE  : "<<mLine.back()<<std::endl;
309       }    
310     }
311     catch (std::exception& e) 
312     {
313        std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
314        if (mFileName.size()) {
315           std::cerr << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
316           std::cerr << "* LINE  : "<<mLine.back()<<std::endl;
317        }    
318     }  
319     catch (...)
320     {
321        std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
322        if (mFileName.size()) {
323           std::cout << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
324           std::cout << "* LINE  : "<<mLine.back()<<std::endl;
325       }    
326     }
327     
328     CloseAllFiles();
329     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
330     bbtkDecTab("Interpreter",9);
331
332     mCommandLine = exm;
333   }
334   //=======================================================================
335
336
337
338   //=======================================================================  
339   /**
340    *
341    */
342 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
343 {
344
345     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
346     bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
347
348     std::vector<std::string> words;
349     SplitLine(line,words);
350     
351     // Empty line
352     if (words.size()<1) 
353     {
354        bbtkDebugDecTab("Interpreter",9);
355        return;
356     }
357
358     // Single line comment : # or //
359     if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') ) 
360     {  
361        bbtkDebugDecTab("Interpreter",9);
362        bbtkMessage("Interpreter",9,"Comment"<<std::endl);
363        return;
364     }
365
366     // Multi line comment ( /* ... */ ) -delimiters on different lines !-
367     
368     if (words[0][0]=='/' && words[0][1]=='*') 
369     {  
370        bbtkDebugDecTab("Interpreter",9);
371        bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
372        insideComment = true;
373        return;
374     }
375
376     if (words[0][0]=='*' && words[0][1]=='/') 
377     {  
378        bbtkDebugDecTab("Interpreter",9);
379        bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
380        if ( !insideComment ) {
381           bbtkDebugDecTab("Interpreter",9);
382           bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);       
383        }
384        insideComment = false;
385        return;
386     }
387
388     if (insideComment) 
389     {  
390        bbtkDebugDecTab("Interpreter",9);
391        bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
392        return;
393     }
394                 
395     // Command 
396     CommandInfoType command;
397     InterpretCommand(words,command);
398
399     bbtkDebugMessage("Interpreter",9,
400                      "Command='"<<command.keyword
401                       <<"' code="<<command.code<<std::endl); 
402     int level=0;
403     std::string left,right,left2,right2;
404     std::string filename;
405     switch (command.code) 
406     {
407       case cNew :
408              mExecuter->Create(words[1],words[2]);
409              break;
410         
411       case cDelete :
412              // TO DO !!
413              // mExecuter->Remove(words[1]);
414              break;
415         
416       case cConnect :
417              Utilities::SplitAroundFirstDot(words[1],left,right);
418              Utilities::SplitAroundFirstDot(words[2],left2,right2);      
419              mExecuter->Connect(left,right,left2,right2);
420              break;
421         
422       case cDefine :
423              if (mFileName.size()>0) 
424              {
425                 filename = Utilities::get_file_name(mFileName.back());
426              }
427              if (words.size()==2) 
428              {
429                 mExecuter->Define(words[1],"user",filename);
430              }
431              else 
432              {
433                mExecuter->Define(words[1],words[2],filename);
434              }
435              break;
436         
437       case cEndDefine :
438              mExecuter->EndDefine();
439              break;
440         
441       case cPrint :
442              Print(words[1]); /// \todo use mExecuter 
443              break;
444         
445       case cExec :
446              if (words[1]=="freeze") 
447            mExecuter->SetNoExecMode(true);
448              else if (words[1]=="unfreeze") 
449            mExecuter->SetNoExecMode(false);
450              else 
451            mExecuter->Update(words[1]);
452              break;
453         
454       case cInput :
455              Utilities::SplitAroundFirstDot(words[2],left,right);
456              mExecuter->DefineInput(words[1],left,right,words[3]);
457              break;
458         
459       case cOutput :
460              Utilities::SplitAroundFirstDot(words[2],left,right);
461              mExecuter->DefineOutput(words[1],left,right,words[3]);
462              break;
463         
464       case cSet :
465              Utilities::SplitAroundFirstDot(words[1],left,right);
466              mExecuter->Set(left,right,words[2]);
467              break;
468         
469       case cAuthor :
470              mExecuter->Author(words[1]);
471              break;
472         
473       case cDescription :
474              mExecuter->Description(words[1]);
475              break;
476         
477       case cHelp :
478              Help(words);
479              break;
480         
481       case cMessage : 
482              if (words.size()<3) 
483              {
484             bbtk::MessageManager::PrintInfo();
485              }
486              else 
487              {
488            sscanf(words[2].c_str(),"%d",&level);
489            bbtk::MessageManager::SetMessageLevel(words[1],level);
490              }
491              break;
492         
493       case cGraph : 
494              Graph(words);
495              break;
496         
497       case cConfig :
498              if (words.size()>1) // any param for config means verbose = true
499                verbose = true;
500              else
501                verbose = false;
502              Config(verbose);            
503              break;
504         
505       case cReset :  // EED
506              this->mExecuter->Reset();
507              break;
508         
509       case cInclude :
510              if (mCommandLine) 
511              {
512            InterpretFile(words[1], true, verbose); // true : better pass use_config_file
513              }
514              else 
515              {
516             SwitchToFile(words[1], true, verbose); // true : better pass use_config_file
517              }
518              break;
519         
520       case cLoad:
521              LoadPackage(words[1], true, verbose); // true : better pass use_config_file
522              break;
523         
524       case cUnload:
525              UnLoadPackage(words[1]);
526              break;
527         
528       case cQuit :
529              throw QuitException();
530              break;
531         
532       case cWorkspace :
533              if (words.size() == 2) 
534              {
535                 if (words[1]=="freeze")        mExecuter->SetNoExecMode(true);
536                 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
537              }
538              else 
539              {
540                 mExecuter->SetWorkspaceName(words[2]);
541              }
542              break;
543         
544       default:
545              bbtkInternalError("should not reach here !!!");
546    }
547     
548    bbtkDecTab("Interpreter",9);
549 }
550   //=======================================================================  
551
552
553
554   //=======================================================================
555   void SplitString ( const std::string& str, const std::string& delimiters, 
556                      std::vector<std::string>& tokens)
557   {
558     // Skip delimiters at beginning.
559     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
560     // Find first delimiter.
561     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
562     
563     while (std::string::npos != pos || std::string::npos != lastPos)
564       {
565         // Found a token, add it to the vector.
566         tokens.push_back(str.substr(lastPos, pos - lastPos));
567         // Skip delimiters.  Note the "not_of"
568         lastPos = str.find_first_not_of(delimiters, pos);
569         // Find next delimiter
570         pos = str.find_first_of(delimiters, lastPos);
571       }
572     
573   }
574   //=======================================================================
575
576
577
578   //=======================================================================
579   /**
580    *  
581    */
582 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
583 {
584     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
585  
586     std::string delimiters = "\"";
587     std::vector<std::string> quote;
588     SplitString(str,delimiters,quote);
589
590     delimiters = " \t";
591     std::vector<std::string>::iterator i;
592     for (i=quote.begin(); i!=quote.end(); ) 
593     {
594        SplitString(*i,delimiters,tokens);
595        ++i;
596        if (i!=quote.end()) 
597        {
598         //    bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
599           tokens.push_back(*i);
600           ++i;
601        }
602     }
603
604     for (i=tokens.begin(); i!=tokens.end(); ++i) 
605     {
606        bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
607     }
608     bbtkDebugMessageCont("Interpreter",9,std::endl);
609
610     bbtkDebugDecTab("Interpreter",9);    
611  }
612   //=======================================================================
613
614
615   //=======================================================================
616   // Replaces substrings "\\n" by a real carriage return "\n"
617   void SubsBackslashN ( std::string& s )
618   {
619     //   std::cout << "BEFORE=["<<s<<"]"<<std::endl;
620     std::string ss("\\n");
621     std::string::size_type pos = 0;
622     pos = s.find(ss,0);
623     char* cr = "\n";
624     while ( pos != std::string::npos )
625    {
626       //  std::cout << "*** find one "<<std::endl;
627       s.replace(pos,2,cr,1);
628       pos = s.find(ss, pos-1);
629    } 
630     //    std::cout << "AFTER=["<<s<<"]"<<std::endl;
631   }
632   //=======================================================================
633
634
635   //=======================================================================
636   /**
637    *  
638    */
639   void Interpreter::Print( const std::string& str)
640   {
641     if (mExecuter->GetNoExecMode()) return;
642
643     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
644
645     std::vector<std::string> chains;
646     std::string delimiters("$");
647
648     // Skip delimiters at beginning.
649     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
650     bool is_text = true;
651     if (lastPos>0) is_text = false;
652   
653     // Find first delimiter.
654     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
655     
656     while (std::string::npos != pos || std::string::npos != lastPos)
657     {
658        if (is_text) 
659        {
660           // Found a text token, add it to the vector.
661           chains.push_back(str.substr(lastPos, pos - lastPos));
662           // std::cout << "text='"<<chains.back()<<"'"<<std::endl;
663        }
664        else 
665        {
666        // is an output (between $$) : decode 
667          std::string tok,box,output;
668          tok = str.substr(lastPos, pos - lastPos);
669          Utilities::SplitAroundFirstDot(tok,box,output);
670          chains.push_back( mExecuter->Get(box,output) );
671     //    std::cout << "outp='"<<chains.back()<<"'"<<std::endl;
672        }
673         // Skip delimiters.  Note the "not_of"
674        lastPos = str.find_first_not_of(delimiters, pos);
675         // Find next delimiter
676        pos = str.find_first_of(delimiters, lastPos);
677     //
678        is_text = !is_text;
679      }
680     //    std::cout << "nb="<<chains.size()<<std::endl;
681      std::vector<std::string>::iterator i;
682      for (i= chains.begin(); i!=chains.end(); ++i) 
683      {
684        //  bbtkMessage("Echo",1,*i);
685        SubsBackslashN(*i);
686        std::cout << *i;
687      }
688      std::cout << std::endl;
689      bbtkDebugDecTab("Interpreter",9);    
690  }
691
692   //=======================================================================
693   /**
694    *  
695    */
696
697 // ===================================================================================
698
699
700   void Interpreter::SwitchToFile( const std::string& name,
701                                   bool use_configuration_file, bool verbose)
702   {
703     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
704                          <<name<<"\")"<<std::endl);
705
706     std::vector<std::string> script_paths;
707     std::string libname;  // full path library name
708     std::string pkgname;  // e.g. <scriptname>.bbs
709      
710     pkgname = Utilities::ExtractScriptName(name);
711
712     if (use_configuration_file)
713     {
714       if (verbose)
715          std::cout << "look for : [" << name << "] (use_configuration_file == TRUE)"  << std::endl;
716       script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
717     }
718
719     bool fullnameGiven = false; 
720     bool foundFile     = false;
721     std::string::size_type slash_position = name.find_last_of("/\\");
722   
723     if (slash_position != std::string::npos)
724     {
725       fullnameGiven = true;     
726       libname =  Utilities::ExpandLibName(name, verbose);
727       if (libname != "") {
728         if ( Utilities::FileExists(libname))
729         {
730           foundFile = true;
731         }
732       }
733     }
734     else    // ----------------------- iterate on the paths
735     {
736       std::string path;    
737       std::vector<std::string>::iterator i;
738       for (i=script_paths.begin();i!=script_paths.end();++i)
739       {
740         path = *i;
741
742        // we *really* want '.' to be the current working directory
743         if (path == ".") {
744           char buf[2048]; // for getcwd
745           char * currentDir = getcwd(buf, 2048);
746           std::string cwd(currentDir);        
747           path = currentDir;
748         }
749
750         libname = Utilities::MakePkgnameFromPath(path, pkgname);
751
752       // Check if library exists           
753         if ( ! Utilities::FileExists(libname) )
754         {
755           if (verbose)
756             std::cout <<"   [" <<libname <<"] : doesn't exist" <<std::endl;
757             continue;  // try next path
758         }
759         foundFile = true;
760         break; // a script was found; we stop iterating
761
762       } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
763     }
764
765     std::ifstream* s;
766
767     if (!foundFile)
768     {
769        if (fullnameGiven)
770          if(libname == "")
771             bbtkError("Path \""<<name<<"\" doesn't exist");
772          else
773             bbtkError("Script \""<<libname<<"\" not found");
774        else
775           bbtkError("No \""<<pkgname<<".bbs\" script found");
776        return;    
777     }
778
779     bbtkMessage("Interpreter",1,pkgname<<" loaded"<<std::endl);
780     
781     s = new std::ifstream;
782     s->open(libname.c_str());
783     if (!s->good()) 
784     {
785         bbtkError("Could not open file \""<<libname<<"\"");
786         return;     
787     }
788
789     if (verbose)
790        std::cout << "   -->[" << libname << "] found" << std::endl;
791
792     mFile.push_back(s);
793     mFileName.push_back(libname);
794     mLine.push_back(0);
795   }   
796    
797
798   //=======================================================================
799
800
801   //=======================================================================
802   /**
803    *  
804    */
805   void Interpreter::CloseCurrentFile()
806   {
807     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
808                       <<std::endl);
809     
810     if (mFile.size()==0) 
811     {
812       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
813       return;
814     }
815
816     mFile.back()->close();
817     delete mFile.back();
818     mFile.pop_back();
819     bbtkDebugMessage("Interpreter",9,
820                      " Closing file '"<<mFileName.back()<<"'"<<std::endl);
821     
822     mFileName.pop_back();
823     mLine.pop_back();
824     bbtkDebugMessage("Interpreter",9," Remains "
825                      <<mFile.size()
826                      <<" open"<<std::endl);
827     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
828                      <<std::endl);
829   }
830   //=======================================================================
831
832  //=======================================================================
833   /**
834    *  
835    */
836   void Interpreter::CloseAllFiles()
837   {
838     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
839                       <<std::endl);
840     
841     while (mFile.size() != 0) 
842     {
843       mFile.back()->close();
844       delete mFile.back();
845       mFile.pop_back();
846       bbtkDebugMessage("Interpreter",9,
847                       " Closing file '"<<mFileName.back()<<"'"<<std::endl);
848       mFileName.pop_back();
849       mLine.pop_back();
850     }
851     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
852                       <<std::endl);
853   }
854   //=======================================================================
855
856
857
858   //=======================================================================
859   /**
860    *  
861    */
862   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
863                                       CommandInfoType& info )
864   {
865     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
866     
867     // searches the command keyword
868     CommandDictType::iterator c;
869     c = mCommandDict.find(words[0]);
870     if ( c == mCommandDict.end() ) {
871       bbtkError(words[0]<<" : unknown command");
872     }
873
874     // tests the number of args 
875     if ( ( words.size()-1 < c->second.argmin ) ||
876          ( words.size()-1 > c->second.argmax ) )
877     {
878        HelpCommand(words[0]);
879        bbtkError(words[0]<<" : wrong number of arguments");
880     }
881
882     info = c->second;
883     bbtkDecTab("Interpreter",9);
884   }
885   //=======================================================================
886
887
888   //=======================================================================
889   /// Displays help on all the commands
890 void Interpreter::Help(const std::vector<std::string>& words)
891 {
892     unsigned int nbarg = words.size()-1;
893     
894     if (nbarg==0) 
895     {
896        HelpCommands();
897     }
898     else if (nbarg==1) 
899     {
900       if (words[1]=="packages") 
901       {
902          PrintPackages(true);
903          return;
904       }
905       try 
906       {
907           HelpCommand(words[1]);
908       }
909       catch (bbtk::Exception e) 
910       {
911          try 
912          {
913             HelpPackage(words[1]);
914          }
915          catch (bbtk::Exception f) 
916          {
917             try 
918             {
919                HelpBlackBox(words[1]);
920             }
921            catch (bbtk::Exception g) 
922            {
923               try
924               {
925                  this->mExecuter->ShowRelations(words[1],"0","9999");
926               }
927               catch (bbtk::Exception h){
928                 bbtkError("\""<<words[1].c_str()
929                           <<"\" is not a known command, package, black box type or black box name");
930               }
931            }
932          }
933        }
934     }
935     else if (nbarg==2) 
936     {
937       if (words[2]=="all")
938       {
939          if ( words[1]=="packages" )
940          {
941             PrintPackages(true,true);
942             return;
943           }
944          try 
945          {
946             HelpPackage(words[1],true);
947          }
948          catch (bbtk::Exception f) 
949          {
950          }
951      }
952      else 
953      {
954         HelpCommand(words[0]);
955         bbtkError(words[0]<<" : syntax error");
956      }
957   }
958   else 
959   {
960      bbtkError("Should not reach here !!!");
961   }
962 }
963   //=======================================================================
964
965    //===================================================================    
966   /// Displays the Configuration
967   void Interpreter::Config( bool verbose ) const
968   {
969     bbtkDebugMessageInc("Core",9,"Factory::Config"<<std::endl);
970     
971     ConfigurationFile cf = ConfigurationFile::GetInstance();
972     
973     const std::string config_xml_full_path      = cf.Get_config_xml_full_path();    
974     const std::string description               = cf.Get_description();
975     const std::string url                       = cf.Get_url();
976     const std::string data_path                 = cf.Get_data_path();
977     const std::string default_doc_tmp           = cf.Get_default_doc_tmp();    
978     const std::string file_separator            = cf.Get_file_separator();    
979     const std::vector<std::string>bbs_paths     = cf.Get_bbs_paths();
980     const std::vector<std::string>package_paths = cf.Get_package_paths();
981     
982     bbtkMessage("Help",1, "============="   << std::endl);           
983     bbtkMessage("Help",1, "Configuration"   << std::endl);
984     bbtkMessage("Help",1, "============="   << std::endl);
985     bbtkMessage("Help",1, "bbtk_config.xml   : [" << config_xml_full_path  << "]" << std::endl); 
986     bbtkMessage("Help",1, "Documentation Url : [" << url             << "]" << std::endl);
987     bbtkMessage("Help",1, "Data Path         : [" << data_path       << "]" << std::endl);
988     bbtkMessage("Help",1, "Default Doc_tmp   : [" << default_doc_tmp << "]" << std::endl);
989     bbtkMessage("Help",1, "File Separator    : [" << file_separator  << "]" << std::endl);
990
991     std::vector<std::string>::const_iterator i;
992            
993     bbtkMessage("Help",1, "BBS Paths   " << std::endl);     
994     for (i = bbs_paths.begin(); i!=bbs_paths.end(); ++i )
995     {
996       bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
997     }    
998     
999     bbtkMessage("Help",1, "PACKAGE Paths : " << std::endl);     
1000     for (i = package_paths.begin(); i!=package_paths.end(); ++i )
1001     {
1002       bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1003     }
1004
1005     bbtkDebugDecTab("Core",9);
1006   }  
1007
1008   //=======================================================================
1009   /// Displays help on all the commands
1010   void Interpreter::HelpCommands()
1011   {
1012     std::cout << "Available commands :" << std::endl;
1013     CommandDictType::iterator i;
1014     for ( i =  mCommandDict.begin();
1015           i != mCommandDict.end();
1016         ++i) {
1017               std::cout << " " << i->first << std::endl;
1018       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1019       //     std::cout << "    " << i->second.help << std::endl;
1020  
1021     }
1022   }
1023   //=======================================================================
1024
1025
1026   //=======================================================================
1027   /// Displays help on a particular commands
1028   void Interpreter::HelpCommand(const std::string& s)
1029   {
1030     CommandDictType::iterator c;
1031     c = mCommandDict.find(s);
1032     if ( c == mCommandDict.end() ) {
1033       bbtkError(s<<" : Unknown command");
1034     }
1035     //    std::cout << " " << s << " : "<<  std::endl;
1036     //    CommandParamDictType::iterator i;
1037     //    for ( i =  c->second.begin();
1038     //      i != c->second.end();
1039     //      ++i) {
1040     std::cout << " usage : " << c->second.syntax << std::endl;
1041     std::cout << "  " << c->second.help << std::endl;
1042     
1043   }
1044   //=======================================================================
1045
1046
1047   //=======================================================================
1048   /// Fills the vector commands with the commands which 
1049   /// have the first n chars of buf for prefix
1050   /// TODO : skip initial spaces in buf and also return the position of first
1051   /// non blank char in buf
1052   void Interpreter::FindCommandsWithPrefix( char* buf,
1053                                             int n,
1054                                             std::vector<std::string>& commands )
1055   {
1056     CommandDictType::const_iterator i;
1057     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1058     {
1059       if ((i->first).find(buf,0,n) == 0) 
1060         commands.push_back(i->first);
1061     }
1062   }
1063   //=======================================================================
1064
1065
1066   
1067   //=======================================================================
1068 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1069   
1070   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1071   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1072   
1073   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1074   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1075   // E.G. STORE THIS IN bbtk_config.xml
1076 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1077 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1078 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1079 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1080 #define BBTK_BACKSPACE_KBCODE   0x00000008
1081 #define BBTK_DEL_KBCODE         0x0000007F
1082 #define BBTK_SPACE_KBCODE       0x00000020 
1083
1084   //=======================================================================
1085   void Interpreter::GetLineFromPrompt(std::string& s)
1086   {
1087     int c;
1088     int ind=0;
1089     
1090     int MAX_LINE_SIZE = 160;
1091     int MAX_HISTORY_SIZE = 100;
1092     
1093     char* newline = new char[MAX_LINE_SIZE];
1094     memset(newline,0,MAX_LINE_SIZE);
1095     char* histline = new char[MAX_LINE_SIZE];
1096     memset(histline,0,MAX_LINE_SIZE);
1097     
1098     char* line = newline;
1099     int hist = mHistory.size();
1100     
1101     
1102     write(1,"> ",2);
1103     while(1)
1104     {
1105        c=0;
1106        read ( STDIN_FILENO, &c, 4) ;
1107
1108        bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1109
1110        // Printable character
1111        if ( (ind<MAX_LINE_SIZE-1) &&
1112             ( c >= BBTK_SPACE_KBCODE ) && 
1113             ( c <  BBTK_DEL_KBCODE )) 
1114        {
1115           PrintChar(c);
1116           line[ind++]=c;
1117        }
1118       // CR
1119        else if (c=='\n')
1120        {
1121        // delete the unused line
1122           if (line==newline)
1123               delete histline;
1124           else
1125               delete newline;
1126    
1127     // empty lines are not stored in from history
1128           if (strlen(line)) 
1129           {
1130                 // if history too long : delete oldest command
1131                 if (mHistory.size()>MAX_HISTORY_SIZE) 
1132                   {
1133                     delete mHistory.front();
1134                     mHistory.pop_front();
1135                   }
1136                 mHistory.push_back(line);
1137           }
1138     
1139           break;
1140         }
1141         // Backspace
1142         else if ( (ind>0) && 
1143                   ((c == BBTK_BACKSPACE_KBCODE) ||
1144                    (c == BBTK_DEL_KBCODE)) )
1145           {
1146             line[ind--]=' ';
1147             BackSpace();
1148           }
1149         // Tab 
1150         else if (c=='\t')
1151           {
1152             // TODO : Command completion  
1153             std::vector<std::string> commands;
1154             FindCommandsWithPrefix( line,ind,commands);
1155             if (commands.size()==1) 
1156               {
1157                 std::string com = *commands.begin();
1158                 for (; ind<com.size(); ++ind) 
1159                   {
1160                     PrintChar(com[ind]); 
1161                     line[ind]=com[ind];
1162                   }
1163                 PrintChar(' '); 
1164                 line[ind++]=' ';
1165               }
1166             else if (commands.size()>1) 
1167               {
1168                 std::vector<std::string>::iterator i;
1169                 write(1,"\n",1);
1170                 for (i=commands.begin();i!=commands.end();++i) 
1171                   {
1172                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1173                     PrintChar(' ');
1174                   }
1175                 write(STDOUT_FILENO,"\n> ",3);
1176                 //for (int j=0;j<ind;++j) 
1177                   //{
1178                     write(STDOUT_FILENO,line,ind); 
1179                     //  }
1180               }
1181           }
1182         // Arrow up : back in history
1183         else if (c==BBTK_UP_ARROW_KBCODE)
1184           {
1185             if (hist) 
1186               {
1187                 // erase current line
1188                 while (ind--) BackSpace();
1189                 // 
1190                 hist--;
1191                 // 
1192                 strcpy(histline,mHistory[hist]);
1193                 line = histline;
1194                 ind = strlen(line);
1195                 
1196                 write(STDOUT_FILENO,line,ind);
1197               }
1198           }
1199         // Arrow down : down in history
1200         else if (c==BBTK_DOWN_ARROW_KBCODE)
1201           {
1202             if (hist<mHistory.size()-1) 
1203               {
1204                 // erase current line
1205                 while (ind--) BackSpace();
1206                 // 
1207                 hist++;
1208                 // 
1209                 strcpy(histline,mHistory[hist]);
1210                 line = histline;
1211                 ind = strlen(line);
1212                 
1213                 write(STDOUT_FILENO,line,ind);
1214               }
1215             // end of history : switch back to newline
1216             else if (hist==mHistory.size()-1)
1217               {
1218                 // erase current line
1219                 while (ind--) BackSpace();
1220                 // 
1221                 hist++;
1222                 // 
1223                 line = newline;
1224                 ind = strlen(line);
1225                 
1226                 write(STDOUT_FILENO,line,ind);
1227               }
1228           }
1229         // Arrow right
1230         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1231           {
1232             PrintChar(line[ind]);
1233             ind++;
1234           }
1235         
1236         // Arrow left
1237         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1238           {
1239             PrintChar('\b');
1240             ind--;
1241             
1242           }
1243
1244       }
1245     write(STDOUT_FILENO,"\n\r",2);
1246     
1247     
1248     s = line;
1249     
1250   }
1251 #else
1252
1253   //=======================================================================
1254   void Interpreter::GetLineFromPrompt(std::string& s)
1255   {  
1256     s.clear();
1257
1258     putchar('>');
1259     putchar(' ');
1260
1261     do 
1262     {
1263       char c = getchar();
1264       if (c=='\n') 
1265       {
1266         putchar('\n');
1267         break;
1268       }
1269       if (c=='\t') 
1270       {
1271         // putchar('T');
1272         continue;
1273       }
1274       // putchar(c);
1275       s += c;
1276     } 
1277     while (true);  
1278     
1279   }
1280   //=======================================================================  
1281
1282 #endif
1283
1284
1285
1286   //=======================================================================
1287   void Interpreter::CommandLineInterpreter()
1288   {
1289     bbtkDebugMessageInc("Interpreter",9,
1290                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1291     
1292 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1293     // Initialise the tty in non canonical mode with no echo
1294     // oter remembers the previous settings to restore them after 
1295     struct termios ter,oter;
1296     tcgetattr(0,&ter);
1297     oter=ter;
1298     ter.c_lflag &= ~ECHO;
1299     ter.c_lflag &= ~ICANON;
1300     ter.c_cc[VMIN]=1;
1301     ter.c_cc[VTIME]=0;
1302     tcsetattr(0,TCSANOW,&ter);
1303 #endif
1304     
1305     mCommandLine = true;
1306     bool again = true;
1307     bool insideComment = false; // for multiline comment  
1308     do 
1309     {
1310       try 
1311       {
1312         std::string line;
1313         GetLineFromPrompt(line);
1314         InterpretLine(line, insideComment);
1315       }
1316       catch (QuitException e)
1317       {
1318         again = false;
1319       }
1320       catch (bbtk::Exception e) 
1321       {
1322         e.Print();
1323       }
1324         catch (std::exception& e) 
1325       {
1326         std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
1327       }
1328       catch (...)
1329       {
1330         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1331       }
1332     }
1333     while (again);
1334   
1335 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1336     tcsetattr(0,TCSANOW,&oter);
1337 #endif
1338   
1339     std::cout << "Good bye !" << std::endl;
1340     
1341     bbtkDebugDecTab("Interpreter",9);
1342   }
1343
1344   //=======================================================================
1345   void Interpreter::Graph(const std::vector<std::string>& words)
1346   {
1347     std::string page;
1348     bool system_display = true;
1349
1350 #ifdef _USE_WXWIDGETS_
1351     if ( WxConsole::GetInstance() != 0 ) system_display = false; 
1352 #endif
1353  
1354     if (words.size()==1) 
1355     {
1356       page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1357     }
1358     else if (words.size()==2) 
1359     {
1360       page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1361     }
1362     else if (words.size()==3) 
1363     {
1364       page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1365     }
1366     else if (words.size()==4) 
1367     {
1368       page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1369     } 
1370     else if (words.size()==5) 
1371     {
1372       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1373     } 
1374     else if (words.size()==6) 
1375     {
1376       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1377     } 
1378     else if (words.size()==7) 
1379     {
1380       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1381     } 
1382
1383 #ifdef _USE_WXWIDGETS_
1384     if ( WxConsole::GetInstance() != 0 )
1385       WxConsole::GetInstance()->ShowHtmlPage(page);
1386 #endif
1387   }
1388   //=======================================================================
1389
1390
1391 }//namespace
1392
1393