]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
Now we may again use absolute/relative paths for scripts and packages
[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 09:12:49 $
7   Version:   $Revision: 1.4 $
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   // 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 std::cout << "pkgname [" << pkgname << "] name [" << name << "]" << std::endl;
719     if (use_configuration_file)
720     {
721       if (verbose)
722          std::cout << "look for : [" << name << "] (use_configuration_file == TRUE)"  << std::endl;
723       script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
724     }
725
726     bool fullnameGiven = false; 
727     bool foundFile     = false;
728     std::string::size_type slash_position = name.find_last_of("/\\");
729             
730     if (slash_position != std::string::npos)
731     {       // ------------------------------------- check user supplied location 
732       fullnameGiven = true;
733       libname =  Utilities::ExpandLibName(name, verbose);
734       if (libname != "") {
735         if ( Utilities::FileExists(libname))
736         {
737           foundFile = true;
738         }
739       }
740     }
741     else    // ------------------------------------- iterate on the paths
742     {
743       std::string path;
744       std::vector<std::string>::iterator i;
745       for (i=script_paths.begin();i!=script_paths.end();++i)
746       {
747         path = *i;
748
749        // we *really* want '.' to be the current working directory
750         if (path == ".") {
751           char buf[2048]; // for getcwd
752           char * currentDir = getcwd(buf, 2048);
753           std::string cwd(currentDir);
754           path = currentDir;
755         }
756
757         libname = Utilities::MakePkgnameFromPath(path, pkgname);
758
759       // Check if library exists           
760         if ( ! Utilities::FileExists(libname) )
761         {
762         // The following is *NOT* a debug time message :
763         // It's a user intended message.
764         // Please don't remove it.
765           if (verbose)
766             std::cout <<"   [" <<libname <<"] : doesn't exist" <<std::endl;
767           continue;  // try next path
768         }
769         foundFile = true;
770         break; // a script was found; we stop iterating
771
772       } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
773     }
774
775     std::ifstream* s;
776
777     if (!foundFile)
778     {
779        if (fullnameGiven)
780          if(libname == "")
781             bbtkError("Path ["<<name<<"] doesn't exist");
782          else
783             bbtkError("Script ["<<libname<<"] not found");
784        else
785           bbtkError("No ["<<pkgname<<".bbs] script found");
786        return;    
787     }
788
789     bbtkMessage("Interpreter",1,pkgname<<" loaded"<<std::endl);
790     
791     s = new std::ifstream;
792     s->open(libname.c_str());
793     if (!s->good()) 
794     {
795         bbtkError("Could not open file ["<<libname<<"]");
796         return;     
797     }
798
799     if (verbose)
800        std::cout << "   -->[" << libname << "] found" << std::endl;
801
802     mFile.push_back(s);
803     mFileName.push_back(libname);
804     mLine.push_back(0);
805   }   
806    
807
808   //=======================================================================
809
810
811   //=======================================================================
812   /**
813    *  
814    */
815   void Interpreter::CloseCurrentFile()
816   {
817     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
818                       <<std::endl);
819     
820     if (mFile.size()==0) 
821     {
822       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
823       return;
824     }
825
826     mFile.back()->close();
827     delete mFile.back();
828     mFile.pop_back();
829     bbtkDebugMessage("Interpreter",9,
830                      " Closing file '"<<mFileName.back()<<"'"<<std::endl);
831     
832     mFileName.pop_back();
833     mLine.pop_back();
834     bbtkDebugMessage("Interpreter",9," Remains "
835                      <<mFile.size()
836                      <<" open"<<std::endl);
837     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
838                      <<std::endl);
839   }
840   //=======================================================================
841
842  //=======================================================================
843   /**
844    *  
845    */
846   void Interpreter::CloseAllFiles()
847   {
848     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
849                       <<std::endl);
850     
851     while (mFile.size() != 0) 
852     {
853       mFile.back()->close();
854       delete mFile.back();
855       mFile.pop_back();
856       bbtkDebugMessage("Interpreter",9,
857                       " Closing file '"<<mFileName.back()<<"'"<<std::endl);
858       mFileName.pop_back();
859       mLine.pop_back();
860     }
861     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
862                       <<std::endl);
863   }
864   //=======================================================================
865
866
867
868   //=======================================================================
869   /**
870    *  
871    */
872   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
873                                       CommandInfoType& info )
874   {
875     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
876     
877     // searches the command keyword
878     CommandDictType::iterator c;
879     c = mCommandDict.find(words[0]);
880     if ( c == mCommandDict.end() ) {
881       bbtkError(words[0]<<" : unknown command");
882     }
883
884     // tests the number of args 
885     if ( ( words.size()-1 < c->second.argmin ) ||
886          ( words.size()-1 > c->second.argmax ) )
887     {
888        HelpCommand(words[0]);
889        bbtkError(words[0]<<" : wrong number of arguments");
890     }
891
892     info = c->second;
893     bbtkDecTab("Interpreter",9);
894   }
895   //=======================================================================
896
897
898   //=======================================================================
899   /// Displays help on all the commands
900 void Interpreter::Help(const std::vector<std::string>& words)
901 {
902     unsigned int nbarg = words.size()-1;
903     
904     if (nbarg==0) 
905     {
906        HelpCommands();
907     }
908     else if (nbarg==1) 
909     {
910       if (words[1]=="packages") 
911       {
912          PrintPackages(true);
913          return;
914       }
915       try 
916       {
917           HelpCommand(words[1]);
918       }
919       catch (bbtk::Exception e) 
920       {
921          try 
922          {
923             HelpPackage(words[1]);
924          }
925          catch (bbtk::Exception f) 
926          {
927             try 
928             {
929                HelpBlackBox(words[1]);
930             }
931            catch (bbtk::Exception g) 
932            {
933               try
934               {
935                  this->mExecuter->ShowRelations(words[1],"0","9999");
936               }
937               catch (bbtk::Exception h){
938                 bbtkError("\""<<words[1].c_str()
939                           <<"\" is not a known command, package, black box type or black box name");
940               }
941            }
942          }
943        }
944     }
945     else if (nbarg==2) 
946     {
947       if (words[2]=="all")
948       {
949          if ( words[1]=="packages" )
950          {
951             PrintPackages(true,true);
952             return;
953           }
954          try 
955          {
956             HelpPackage(words[1],true);
957          }
958          catch (bbtk::Exception f) 
959          {
960          }
961      }
962      else 
963      {
964         HelpCommand(words[0]);
965         bbtkError(words[0]<<" : syntax error");
966      }
967   }
968   else 
969   {
970      bbtkError("Should not reach here !!!");
971   }
972 }
973   //=======================================================================
974
975    //===================================================================    
976   /// Displays the Configuration
977   void Interpreter::Config( bool verbose ) const
978   {
979     bbtkDebugMessageInc("Core",9,"Factory::Config"<<std::endl);
980     
981     ConfigurationFile cf = ConfigurationFile::GetInstance();
982     
983     const std::string config_xml_full_path      = cf.Get_config_xml_full_path();    
984     const std::string description               = cf.Get_description();
985     const std::string url                       = cf.Get_url();
986     const std::string data_path                 = cf.Get_data_path();
987     const std::string default_doc_tmp           = cf.Get_default_doc_tmp();    
988     const std::string file_separator            = cf.Get_file_separator();    
989     const std::vector<std::string>bbs_paths     = cf.Get_bbs_paths();
990     const std::vector<std::string>package_paths = cf.Get_package_paths();
991     
992     bbtkMessage("Help",1, "============="   << std::endl);           
993     bbtkMessage("Help",1, "Configuration"   << std::endl);
994     bbtkMessage("Help",1, "============="   << std::endl);
995     bbtkMessage("Help",1, "bbtk_config.xml   : [" << config_xml_full_path  << "]" << std::endl); 
996     bbtkMessage("Help",1, "Documentation Url : [" << url             << "]" << std::endl);
997     bbtkMessage("Help",1, "Data Path         : [" << data_path       << "]" << std::endl);
998     bbtkMessage("Help",1, "Default Doc_tmp   : [" << default_doc_tmp << "]" << std::endl);
999     bbtkMessage("Help",1, "File Separator    : [" << file_separator  << "]" << std::endl);
1000
1001     std::vector<std::string>::const_iterator i;
1002            
1003     bbtkMessage("Help",1, "BBS Paths   " << std::endl);     
1004     for (i = bbs_paths.begin(); i!=bbs_paths.end(); ++i )
1005     {
1006       bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1007     }    
1008     
1009     bbtkMessage("Help",1, "PACKAGE Paths : " << std::endl);     
1010     for (i = package_paths.begin(); i!=package_paths.end(); ++i )
1011     {
1012       bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1013     }
1014
1015     bbtkDebugDecTab("Core",9);
1016   }  
1017
1018   //=======================================================================
1019   /// Displays help on all the commands
1020   void Interpreter::HelpCommands()
1021   {
1022     std::cout << "Available commands :" << std::endl;
1023     CommandDictType::iterator i;
1024     for ( i =  mCommandDict.begin();
1025           i != mCommandDict.end();
1026         ++i) {
1027               std::cout << " " << i->first << std::endl;
1028       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1029       //     std::cout << "    " << i->second.help << std::endl;
1030  
1031     }
1032   }
1033   //=======================================================================
1034
1035
1036   //=======================================================================
1037   /// Displays help on a particular commands
1038   void Interpreter::HelpCommand(const std::string& s)
1039   {
1040     CommandDictType::iterator c;
1041     c = mCommandDict.find(s);
1042     if ( c == mCommandDict.end() ) {
1043       bbtkError(s<<" : Unknown command");
1044     }
1045     //    std::cout << " " << s << " : "<<  std::endl;
1046     //    CommandParamDictType::iterator i;
1047     //    for ( i =  c->second.begin();
1048     //      i != c->second.end();
1049     //      ++i) {
1050     std::cout << " usage : " << c->second.syntax << std::endl;
1051     std::cout << "  " << c->second.help << std::endl;
1052     
1053   }
1054   //=======================================================================
1055
1056
1057   //=======================================================================
1058   /// Fills the vector commands with the commands which 
1059   /// have the first n chars of buf for prefix
1060   /// TODO : skip initial spaces in buf and also return the position of first
1061   /// non blank char in buf
1062   void Interpreter::FindCommandsWithPrefix( char* buf,
1063                                             int n,
1064                                             std::vector<std::string>& commands )
1065   {
1066     CommandDictType::const_iterator i;
1067     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1068     {
1069       if ((i->first).find(buf,0,n) == 0) 
1070         commands.push_back(i->first);
1071     }
1072   }
1073   //=======================================================================
1074
1075
1076   
1077   //=======================================================================
1078 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1079   
1080   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1081   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1082   
1083   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1084   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1085   // E.G. STORE THIS IN bbtk_config.xml
1086 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1087 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1088 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1089 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1090 #define BBTK_BACKSPACE_KBCODE   0x00000008
1091 #define BBTK_DEL_KBCODE         0x0000007F
1092 #define BBTK_SPACE_KBCODE       0x00000020 
1093
1094   //=======================================================================
1095   void Interpreter::GetLineFromPrompt(std::string& s)
1096   {
1097     int c;
1098     int ind=0;
1099     
1100     int MAX_LINE_SIZE = 160;
1101     int MAX_HISTORY_SIZE = 100;
1102     
1103     char* newline = new char[MAX_LINE_SIZE];
1104     memset(newline,0,MAX_LINE_SIZE);
1105     char* histline = new char[MAX_LINE_SIZE];
1106     memset(histline,0,MAX_LINE_SIZE);
1107     
1108     char* line = newline;
1109     int hist = mHistory.size();
1110     
1111     
1112     write(1,"> ",2);
1113     while(1)
1114     {
1115        c=0;
1116        read ( STDIN_FILENO, &c, 4) ;
1117
1118        bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1119
1120        // Printable character
1121        if ( (ind<MAX_LINE_SIZE-1) &&
1122             ( c >= BBTK_SPACE_KBCODE ) && 
1123             ( c <  BBTK_DEL_KBCODE )) 
1124        {
1125           PrintChar(c);
1126           line[ind++]=c;
1127        }
1128       // CR
1129        else if (c=='\n')
1130        {
1131        // delete the unused line
1132           if (line==newline)
1133               delete histline;
1134           else
1135               delete newline;
1136    
1137     // empty lines are not stored in from history
1138           if (strlen(line)) 
1139           {
1140                 // if history too long : delete oldest command
1141                 if (mHistory.size()>MAX_HISTORY_SIZE) 
1142                   {
1143                     delete mHistory.front();
1144                     mHistory.pop_front();
1145                   }
1146                 mHistory.push_back(line);
1147           }
1148     
1149           break;
1150         }
1151         // Backspace
1152         else if ( (ind>0) && 
1153                   ((c == BBTK_BACKSPACE_KBCODE) ||
1154                    (c == BBTK_DEL_KBCODE)) )
1155           {
1156             line[ind--]=' ';
1157             BackSpace();
1158           }
1159         // Tab 
1160         else if (c=='\t')
1161           {
1162             // TODO : Command completion  
1163             std::vector<std::string> commands;
1164             FindCommandsWithPrefix( line,ind,commands);
1165             if (commands.size()==1) 
1166               {
1167                 std::string com = *commands.begin();
1168                 for (; ind<com.size(); ++ind) 
1169                   {
1170                     PrintChar(com[ind]); 
1171                     line[ind]=com[ind];
1172                   }
1173                 PrintChar(' '); 
1174                 line[ind++]=' ';
1175               }
1176             else if (commands.size()>1) 
1177               {
1178                 std::vector<std::string>::iterator i;
1179                 write(1,"\n",1);
1180                 for (i=commands.begin();i!=commands.end();++i) 
1181                   {
1182                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1183                     PrintChar(' ');
1184                   }
1185                 write(STDOUT_FILENO,"\n> ",3);
1186                 //for (int j=0;j<ind;++j) 
1187                   //{
1188                     write(STDOUT_FILENO,line,ind); 
1189                     //  }
1190               }
1191           }
1192         // Arrow up : back in history
1193         else if (c==BBTK_UP_ARROW_KBCODE)
1194           {
1195             if (hist) 
1196               {
1197                 // erase current line
1198                 while (ind--) BackSpace();
1199                 // 
1200                 hist--;
1201                 // 
1202                 strcpy(histline,mHistory[hist]);
1203                 line = histline;
1204                 ind = strlen(line);
1205                 
1206                 write(STDOUT_FILENO,line,ind);
1207               }
1208           }
1209         // Arrow down : down in history
1210         else if (c==BBTK_DOWN_ARROW_KBCODE)
1211           {
1212             if (hist<mHistory.size()-1) 
1213               {
1214                 // erase current line
1215                 while (ind--) BackSpace();
1216                 // 
1217                 hist++;
1218                 // 
1219                 strcpy(histline,mHistory[hist]);
1220                 line = histline;
1221                 ind = strlen(line);
1222                 
1223                 write(STDOUT_FILENO,line,ind);
1224               }
1225             // end of history : switch back to newline
1226             else if (hist==mHistory.size()-1)
1227               {
1228                 // erase current line
1229                 while (ind--) BackSpace();
1230                 // 
1231                 hist++;
1232                 // 
1233                 line = newline;
1234                 ind = strlen(line);
1235                 
1236                 write(STDOUT_FILENO,line,ind);
1237               }
1238           }
1239         // Arrow right
1240         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1241           {
1242             PrintChar(line[ind]);
1243             ind++;
1244           }
1245         
1246         // Arrow left
1247         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1248           {
1249             PrintChar('\b');
1250             ind--;
1251             
1252           }
1253
1254       }
1255     write(STDOUT_FILENO,"\n\r",2);
1256     
1257     
1258     s = line;
1259     
1260   }
1261 #else
1262
1263   //=======================================================================
1264   void Interpreter::GetLineFromPrompt(std::string& s)
1265   {  
1266     s.clear();
1267
1268     putchar('>');
1269     putchar(' ');
1270
1271     do 
1272     {
1273       char c = getchar();
1274       if (c=='\n') 
1275       {
1276         putchar('\n');
1277         break;
1278       }
1279       if (c=='\t') 
1280       {
1281         // putchar('T');
1282         continue;
1283       }
1284       // putchar(c);
1285       s += c;
1286     } 
1287     while (true);  
1288     
1289   }
1290   //=======================================================================  
1291
1292 #endif
1293
1294
1295
1296   //=======================================================================
1297   void Interpreter::CommandLineInterpreter()
1298   {
1299     bbtkDebugMessageInc("Interpreter",9,
1300                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1301     
1302 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1303     // Initialise the tty in non canonical mode with no echo
1304     // oter remembers the previous settings to restore them after 
1305     struct termios ter,oter;
1306     tcgetattr(0,&ter);
1307     oter=ter;
1308     ter.c_lflag &= ~ECHO;
1309     ter.c_lflag &= ~ICANON;
1310     ter.c_cc[VMIN]=1;
1311     ter.c_cc[VTIME]=0;
1312     tcsetattr(0,TCSANOW,&ter);
1313 #endif
1314     
1315     mCommandLine = true;
1316     bool again = true;
1317     bool insideComment = false; // for multiline comment  
1318     do 
1319     {
1320       try
1321       {
1322         std::string line;
1323         GetLineFromPrompt(line);
1324         InterpretLine(line, insideComment);
1325       }
1326       catch (QuitException e)
1327       {
1328         again = false;
1329       }
1330       catch (bbtk::Exception e) 
1331       {
1332         e.Print();
1333       }
1334         catch (std::exception& e) 
1335       {
1336         std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1337       }
1338       catch (...)
1339       {
1340         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1341       }
1342     }
1343     while (again);
1344   
1345 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1346     tcsetattr(0,TCSANOW,&oter);
1347 #endif
1348   
1349     std::cout << "Good bye !" << std::endl;
1350     
1351     bbtkDebugDecTab("Interpreter",9);
1352   }
1353
1354   //=======================================================================
1355   void Interpreter::Graph(const std::vector<std::string>& words)
1356   {
1357     std::string page;
1358     bool system_display = true;
1359
1360 #ifdef _USE_WXWIDGETS_
1361     if ( WxConsole::GetInstance() != 0 ) system_display = false; 
1362 #endif
1363  
1364     if (words.size()==1) 
1365     {
1366       page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1367     }
1368     else if (words.size()==2) 
1369     {
1370       page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1371     }
1372     else if (words.size()==3) 
1373     {
1374       page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1375     }
1376     else if (words.size()==4) 
1377     {
1378       page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1379     } 
1380     else if (words.size()==5) 
1381     {
1382       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1383     } 
1384     else if (words.size()==6) 
1385     {
1386       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1387     } 
1388     else if (words.size()==7) 
1389     {
1390       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1391     } 
1392
1393 #ifdef _USE_WXWIDGETS_
1394     if ( WxConsole::GetInstance() != 0 )
1395       WxConsole::GetInstance()->ShowHtmlPage(page);
1396 #endif
1397   }
1398   //=======================================================================
1399
1400
1401 }//namespace
1402
1403