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