]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
Create Black Box bbs + .bat + Bug interface Windows
[bbtk.git] / kernel / src / bbtkInterpreter.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkInterpreter.cxx,v $ $
5   Language:  C++
6   Date:      $Date: 2008/03/17 07:04:08 $
7   Version:   $Revision: 1.45 $
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 #include <algorithm>
30 #ifdef CMAKE_HAVE_TERMIOS_H
31 #include <termios.h>
32 #define BBTK_USE_TERMIOS_BASED_PROMPT
33 #endif
34
35 #include <string>
36
37 namespace bbtk
38 {
39
40   //Interpreter* Interpreter::mGlobalInterpreter = NULL;
41
42  //=======================================================================
43  /**
44    *
45    */
46   Interpreter::Interpreter() 
47     :
48 #ifdef _USE_WXWIDGETS_
49     mWxConsole(0),
50 #endif
51     mCommandLine(false)
52   {
53 bufferNb =0;  
54     bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
55     bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
56     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
57  
58     mExecuter = new bbtk::Executer();
59     mExecuter->SetInterpreter(this);
60     
61     // For the time being, comment out previous line, and
62     // uncomment next line to check Transcriptor
63
64     //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
65
66     // Builds the commands dict
67     CommandInfoType info;
68    
69     info.category = "new";
70     info.argmin = 2;
71     info.argmax = 2;
72     info.code = cNew;
73     info.syntax = "new <type> <name>";
74     info.help = "Creates a new black box of type <type> with name <name>";
75     mCommandDict[info.category] = info;
76     
77     info.category = "delete";
78     info.argmin = 1;
79     info.argmax = 1;
80     info.code = cDelete;
81     info.syntax = "delete <box>";
82     info.help = "Deletes the black box of name <box>";
83     mCommandDict[info.category] = info;
84
85     info.category = "connect";
86     info.argmin = 2;
87     info.argmax = 2;
88     info.code = cConnect;
89     info.syntax = "connect <box1.output> <box2.input>";
90     info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
91     mCommandDict[info.category] = info;
92
93     info.category = "print";
94     info.argmin = 1;
95     info.argmax = 1;
96     info.code = cPrint;
97     info.syntax = "print <string>";
98     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').";
99     mCommandDict[info.category] = info;
100
101     info.category = "exec";
102     info.argmin = 1;
103     info.argmax = 2;
104     info.code = cExec;
105     info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
106     info.help = "Executes the black box of name <box> (and connected boxes if needed). If the special category 'freeze' is given then freezes any further execution command. 'unfreeze' reverts to normal execution mode.";
107     mCommandDict[info.category] = info;
108
109     info.category = "package";
110     info.argmin = 1;
111     info.argmax = 1;
112     info.code = cPackage;
113     info.syntax = "package <name>";
114     info.help = "Begins the definition of a package.";
115     mCommandDict[info.category] = info;
116     
117     info.category = "endpackage";
118     info.argmin = 0;
119     info.argmax = 0;
120     info.code = cEndPackage;
121     info.syntax = "endpackage";
122     info.help = "Ends the definition of a package.";
123     mCommandDict[info.category] = info;
124
125     info.category = "define";
126     info.argmin = 1;
127     info.argmax = 2;
128     info.code = cDefine;
129     info.syntax = "define <type> [<package>]";
130     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.";
131     mCommandDict[info.category] = info;
132     
133     info.category = "endefine";
134     info.argmin = 0;
135     info.argmax = 0;
136     info.code = cEndDefine;
137     info.syntax = "endefine";
138     info.help = "Ends the definition of a new type of complex black box";
139     mCommandDict[info.category] = info;
140
141     info.category = "input";
142     info.argmin = 3;
143     info.argmax = 3;
144     info.code = cInput;
145     info.syntax = "input <name> <box.input> <help>";
146     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";
147     mCommandDict[info.category] = info;
148
149     info.category = "output";
150     info.argmin = 3;
151     info.argmax = 3;
152     info.code = cOutput;
153     info.syntax = "output <name> <box.output> <help>";
154     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";
155     mCommandDict[info.category] = info;
156
157     info.category = "set";
158     info.argmin = 2;
159     info.argmax = 2;
160     info.code = cSet;
161     info.syntax = "set <box.input> <value>";
162     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";
163     mCommandDict[info.category] = info;
164    
165     info.category = "config";  // JPR
166     info.argmin = 0;
167     info.argmax = 0;
168     info.code = cConfig;
169     info.syntax = "config";
170     info.help = "Prints the value of all configuration parameters";
171     mCommandDict[info.category] = info;
172
173     info.category = "index";  // LG
174     info.argmin = 0;
175     info.argmax = 2;
176     info.code = cIndex;
177
178     info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
179     info.help = "Creates an html index of known boxes. If filename is provided then save it to the file 'filename'. The default index entries are the initial letters of the names of the boxes. If 'Packages' or 'Categories' is provided then the entries are either the packages names or the categories. If 'Adaptors' is provided then an alphabetical index of all adaptors is created.";
180     mCommandDict[info.category] = info;
181
182     info.category = "reset";  
183     info.argmin = 0;
184     info.argmax = 0;
185     info.code = cReset;
186     info.syntax = "reset";
187     info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
188     mCommandDict[info.category] = info;
189
190     info.category = "author";
191     info.argmin = 1;
192     info.argmax = 1;
193     info.code = cAuthor;
194     info.syntax = "author <string>";
195     info.help = "Adds the string <string> to the author information of the black box being defined";
196     mCommandDict[info.category] = info;
197     
198     info.category = "category"; //JP
199     info.argmin = 1;
200     info.argmax = 1;
201     info.code = cCategory;
202     info.syntax = "category <list of items, separated by ;>";
203     info.help = "Adds the string <string> to the category information of the black box being defined";
204     mCommandDict[info.category] = info;
205
206     info.category = "description";
207     info.argmin = 1;
208     info.argmax = 1;
209     info.code = cDescription;
210     info.syntax = "description <string>";
211     info.help = "Adds the string <string> to the descriptive information of the black box being defined";
212     mCommandDict[info.category] = info;
213
214     info.category = "help";
215     info.argmin = 0;
216     info.argmax = 2;
217     info.code = cHelp;
218     info.syntax = "help";
219     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>";
220     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.";
221     mCommandDict[info.category] = info;
222
223     info.category = "message";
224     info.argmin = 0;
225     info.argmax = 2;
226     info.code = cMessage;
227     info.syntax = "message <kind> <level>";
228     info.help = "Sets the level of the kind of messages <kind> to <level>.\n  If kind='All' then sets the level for all kinds. If no kind nor level is passed then prints info on available kinds of messages and their current level.";  mCommandDict[info.category] = info;
229
230     info.category = "include";
231     info.argmin = 1;
232     info.argmax = 2;
233     info.code = cInclude;
234     info.syntax = "include <filename> [source]";
235     info.help = "Includes the file <filename>.\n  'source' : If the keyword 'source' is provided then informs bbi that the included file is the source of the current box definition (Advanced; used to get the right 'Include' field in html doc of packages 'appli' scripts).";
236     mCommandDict[info.category] = info;
237
238     info.category = "quit";
239     info.argmin = 0;
240     info.argmax = 0;
241     info.code = cQuit;
242     info.syntax = "quit";
243     info.help = "Quits the program (during script execution it stops the complete execution)";
244     mCommandDict[info.category] = info;
245
246     info.category = "load";
247     info.argmin = 1;
248     info.argmax = 1;
249     info.code = cLoad;
250     info.syntax = "load <packagename>";
251     info.help = "Loads the black box package <packagename>";
252     mCommandDict[info.category] = info;
253
254     info.category = "unload";
255     info.argmin = 1;
256     info.argmax = 1;
257     info.code = cUnload;
258     info.syntax = "unload <packagename>";
259     info.help = "Unloads the black box package <packagename>";
260     mCommandDict[info.category] = info;
261
262     info.category = "graph";
263     info.argmin = 0;
264     info.argmax = 6;
265     info.code = cGraph;
266     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 ]]]]]]";
267     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')";
268     mCommandDict[info.category] = info;
269
270     /*
271     info.category = "workspace";
272     info.argmin = 1;
273     info.argmax = 2;
274     info.code = cWorkspace;
275     info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
276     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.";
277     mCommandDict[info.category] = info;
278     */
279
280     bbtkDebugDecTab("Interpreter",9);
281
282   } 
283   //=======================================================================
284   
285   
286   
287   //=======================================================================  
288   /**
289    *  
290    */
291   Interpreter::~Interpreter()
292   {
293     bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
294     delete mExecuter;
295
296     bbtkDebugDecTab("Interpreter",9);
297   }
298   //=======================================================================
299
300
301   //=======================================================================
302   /**
303    *  
304    */
305   void Interpreter::InterpretFile( const std::string& filename )
306   {
307     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
308   //  std::cout << "==========================================Entree InterpretFile ["<<filename<<"] try SwitchToFile "<<std::endl;
309     bool exm = mCommandLine;
310     mCommandLine = false;
311
312     try 
313     {
314       SwitchToFile(filename);
315
316 /*
317       for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
318       {
319          std::cout << "A=== [" << (*it) << "]" << std::endl;
320       }
321 */      
322       bool insideComment = false; // for multiline comment
323       while (mFile.size()>0) 
324       {
325 /*
326          for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
327          {
328             std::cout << "B=== [" << (*it) << "]" << std::endl;
329          }
330 */      
331
332          //while ((mFile.size()>0) && !mFile.back()->eof() ) 
333          //{
334 //       std::cout << "mFile.size() "<< mFile.size() << " mFileName.back() [" << mFileName.back() << "]" <<  std::endl;
335          while (!mFile.back()->eof()) {
336                      mLine.back()++;
337             char buf[500];
338             mFile.back()->getline(buf,500);
339             std::string str(buf);
340 // std::cout << " in InterpretFile mFile.back()->getline [" << str << "]" << std::endl;    
341             int size=str.length();
342             if ( str[ size-1 ]==13  )
343             {
344                str.erase(size-1,1);
345             }
346       
347                 InterpretLine(str, insideComment);
348
349        }//while
350        //if (mFile.size()>0) 
351        CloseCurrentFile();
352       }
353     }
354     catch (QuitException e) 
355     {
356     }
357     catch (bbtk::Exception e) 
358     {
359       std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
360       if (mFileName.size()) {
361          std::cerr << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
362          std::cerr << "* LINE  : "<<mLine.back()<<std::endl;
363       }    
364     }
365     catch (std::exception& e) 
366     {
367        std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
368        if (mFileName.size()) {
369           std::cerr << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
370           std::cerr << "* LINE  : "<<mLine.back()<<std::endl;
371        }    
372     }  
373     catch (...)
374     {
375        std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
376        if (mFileName.size()) {
377           std::cout << "* FILE  : \""<<mFileName.back()<<"\""<<std::endl;
378           std::cout << "* LINE  : "<<mLine.back()<<std::endl;
379       }    
380     }
381
382     CloseAllFiles();
383     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
384     bbtkDecTab("Interpreter",9);
385
386     mCommandLine = exm;
387   }
388   //=======================================================================
389
390
391
392   //=======================================================================  
393   /**
394    *
395    */
396 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
397 {
398     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
399     bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
400
401     std::vector<std::string> words;
402     SplitLine(line,words);
403
404     // Empty line
405     if (words.size()<1) 
406     {
407        bbtkDebugDecTab("Interpreter",9);
408        return;
409     }
410
411     // Single line comment : # or //
412     if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') ) 
413     {  
414        bbtkDebugDecTab("Interpreter",9);
415        bbtkMessage("Interpreter",9,"Comment"<<std::endl);
416        return;
417     }
418
419     // Multi line comment ( /* ... */ ) -delimiters on different lines !-
420     
421     if (words[0][0]=='/' && words[0][1]=='*') 
422     {  
423        bbtkDebugDecTab("Interpreter",9);
424        bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
425        insideComment = true;
426        return;
427     }
428
429     if (words[0][0]=='*' && words[0][1]=='/') 
430     {  
431        bbtkDebugDecTab("Interpreter",9);
432        bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
433        if ( !insideComment ) {
434           bbtkDebugDecTab("Interpreter",9);
435           bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);       
436        }
437        insideComment = false;
438        return;
439     }
440
441     if (insideComment) 
442     {  
443        bbtkDebugDecTab("Interpreter",9);
444        bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
445        return;
446     }
447
448     // Command 
449     CommandInfoType command;
450     InterpretCommand(words,command);
451
452     bbtkDebugMessage("Interpreter",9,
453                      "Command='"<<command.category
454                       <<"' code="<<command.code<<std::endl); 
455     int level=0;
456     std::string left,right,left2,right2;
457     std::string filename;
458     switch (command.code) 
459     {
460       case cNew :
461         mExecuter->Create(words[1],words[2]);
462         break;
463
464       case cDelete :
465         // TO DO !!
466         // mExecuter->Remove(words[1]);
467         break;
468
469       case cConnect :
470         Utilities::SplitAroundFirstDot(words[1],left,right);
471         Utilities::SplitAroundFirstDot(words[2],left2,right2);      
472         mExecuter->Connect(left,right,left2,right2);
473         break;
474
475       case cPackage :
476         mExecuter->BeginPackage(words[1]);
477         break;
478
479       case cEndPackage :
480         mExecuter->EndPackage();
481         break;
482
483       case cDefine :
484         if (mFileName.size()>0) 
485         {
486           filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
487         }
488         if (words.size()==2) 
489         {
490            mExecuter->Define(words[1],"",filename);
491         }
492         else
493         {
494            mExecuter->Define(words[1],words[2],filename);
495         }
496         break;
497
498       case cEndDefine :
499         mExecuter->EndDefine();
500         break;
501
502       case cPrint :
503         Print(words[1]); /// \todo use generate command 
504         break;
505         
506       case cExec :
507         if (words[1]=="freeze") 
508           mExecuter->SetNoExecMode(true);
509         else if (words[1]=="unfreeze") 
510           mExecuter->SetNoExecMode(false);
511         else
512           mExecuter->Update(words[1]);
513         break;
514
515       case cInput :
516         Utilities::SplitAroundFirstDot(words[2],left,right);
517         mExecuter->DefineInput(words[1],left,right,words[3]);
518         break;
519
520       case cOutput :
521         Utilities::SplitAroundFirstDot(words[2],left,right);
522         mExecuter->DefineOutput(words[1],left,right,words[3]);
523         break;
524
525       case cSet :
526         Utilities::SplitAroundFirstDot(words[1],left,right);
527         mExecuter->Set(left,right,words[2]);
528         break;
529
530       case cAuthor :
531         mExecuter->Author(words[1]);
532         break;
533
534       case cCategory :
535         mExecuter->Category(words[1]);
536         break;
537
538       case cIndex :
539         if (words.size()==1)
540              Index("tmp_index.html");
541         else if (words.size()==2)
542              Index(words[1]);
543         else if (words.size()==3)
544              Index(words[1],words[2]);
545         break;
546
547       case cDescription :
548         mExecuter->Description(words[1]);
549         break;
550
551       case cHelp :
552         Help(words);
553         break;
554
555       case cMessage : 
556         if (words.size()<3)
557         {
558            bbtk::MessageManager::PrintInfo();
559         }
560         else
561         {
562            sscanf(words[2].c_str(),"%d",&level);
563            bbtk::MessageManager::SetMessageLevel(words[1],level);
564         }
565         break;
566
567       case cGraph :
568         Graph(words);
569         break;
570
571       case cConfig :
572         Config();
573         break;
574
575       case cReset :  
576         this->mExecuter->Reset();
577         break;
578
579       case cInclude :
580         if (mCommandLine)
581         {
582            InterpretFile(words[1]); 
583         }
584         else
585         {
586             SwitchToFile(words[1]);
587         }
588         // if 'source' was given
589         if (words.size()==3) 
590           {
591             GetExecuter()->SetCurrentFileName(words[1]);
592           }
593         break;
594
595       case cLoad:
596         GetExecuter()->GetFactory()->LoadPackage(words[1]);
597         break;
598
599       case cUnload:
600         GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
601         break;
602
603       case cQuit :
604         delete mExecuter;
605         throw QuitException();
606         break;
607
608       case cWorkspace :
609         if (words.size() == 2) 
610         {
611            if (words[1]=="freeze")        mExecuter->SetNoExecMode(true);
612            else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
613         }
614         else
615         {
616            mExecuter->SetWorkspaceName(words[2]);
617         }
618         break;
619         
620       default:
621         bbtkInternalError("should not reach here !!!");
622    }
623
624    bbtkDecTab("Interpreter",9);
625 }
626   //=======================================================================  
627
628
629
630
631
632   //=======================================================================
633   /**
634    *
635    */
636 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
637 {
638     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
639
640     std::string delimiters = "\"";
641     std::vector<std::string> quote;
642     Utilities::SplitString(str,delimiters,quote);
643
644     delimiters = " \t";
645     std::vector<std::string>::iterator i;
646     for (i=quote.begin(); i!=quote.end(); ) 
647     {
648        Utilities::SplitString(*i,delimiters,tokens);
649        ++i;
650        if (i!=quote.end()) 
651        {
652         //    bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
653           tokens.push_back(*i);
654           ++i;
655        }
656     }
657
658     for (i=tokens.begin(); i!=tokens.end(); ++i) 
659     {
660        bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
661     }
662     bbtkDebugMessageCont("Interpreter",9,std::endl);
663
664     bbtkDebugDecTab("Interpreter",9);
665  }
666   //=======================================================================
667
668
669   //=======================================================================
670   // Replaces substrings "\\n" by a real carriage return "\n"
671   void SubsBackslashN ( std::string& s )
672   {
673     std::string ss("\\n");
674     std::string::size_type pos = 0;
675     pos = s.find(ss,0);
676     char* cr = "\n";
677     while ( pos != std::string::npos )
678     {
679       s.replace(pos,2,cr,1);
680       pos = s.find(ss, pos-1);
681     }
682   }
683   //=======================================================================
684
685
686   //=======================================================================
687   /**
688    *
689    */
690   void Interpreter::Print( const std::string& str)
691   {
692     if (mExecuter->GetNoExecMode()) return;
693
694     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
695
696  // TO DO :
697  // InterpretLine ("load std")
698  // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande 
699  // InterpretLine("new Print _P_") 
700  // InterpretLine("connect _C_.Out _P_.In")
701  // int num = 1
702  
703
704     std::vector<std::string> chains;
705     std::string delimiters("$");
706
707     // Skip delimiters at beginning.
708     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
709     bool is_text = true;
710     if (lastPos>0) is_text = false;
711
712     // Find first delimiter.
713     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
714
715     while (std::string::npos != pos || std::string::npos != lastPos)
716     {
717        if (is_text) 
718        {
719           // Found a text token, add it to the vector.
720           chains.push_back(str.substr(lastPos, pos - lastPos));
721  // std::string token = str.substr(lastPos, pos - lastPos)
722  // InterpretLine("set _C_.In%num% %token%")
723  
724        }
725        else 
726        {
727
728        // is an output (between $$) : decode 
729          std::string tok,box,output;
730          tok = str.substr(lastPos, pos - lastPos);
731          Utilities::SplitAroundFirstDot(tok,box,output);
732          chains.push_back( mExecuter->Get(box,output) );
733
734 // InterpretLine("connect %tok% _C_.In%num%") 
735
736        }
737         // Skip delimiters.  Note the "not_of"
738        lastPos = str.find_first_not_of(delimiters, pos);
739         // Find next delimiter
740        pos = str.find_first_of(delimiters, lastPos);
741     //
742        is_text = !is_text;
743 // num ++;
744      }
745 // InterpretLine("exec _P_")
746 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
747
748      std::vector<std::string>::iterator i;
749      for (i= chains.begin(); i!=chains.end(); ++i) 
750      {
751        //  bbtkMessage("Echo",1,*i);
752        SubsBackslashN(*i);
753        std::cout << *i;
754      }
755      std::cout << std::endl;
756      bbtkDebugDecTab("Interpreter",9);
757  }
758
759   //=======================================================================
760   /**
761    *
762    */
763
764 // ===================================================================================
765
766   void Interpreter::SwitchToFile( const std::string& name )
767   {
768   // Note : in the following :
769   // name : the user supplied name 
770   //      - abreviated name    e.g.       scr   scr.bbs
771   //      - relative full name e.g.       ./scr.bbs   ../../scr.bbs 
772   //      - absolute full name e.g.       /home/usrname/proj/dir/scr.bbs
773   //          same for Windows, with      c:, d: ...
774   //
775   // use ./directory/subdir/scrname.bbs
776   //
777
778     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
779                          <<name<<"\")"<<std::endl);
780
781     std::vector<std::string> script_paths;
782     std::string fullPathScriptName;  // full path script name
783     std::string pkgname;             // e.g. <scriptname>.bbs
784     std::vector<std::string> Filenames;
785
786     // The following is *NOT* a debug time message :
787     // It's a user intended message.
788     // Please don't remove it.
789     bbtkMessage("Interpreter",1,
790         "look for : [" << name
791         << "]" << std::endl);
792     script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
793
794     std::string upath;
795     pkgname = Utilities::ExtractScriptName(name,upath);
796
797     bbtkMessage("Interpreter",1,
798                 "extract : pkgname [" << pkgname
799                  << "] upath [" << upath << "]" << std::endl);
800     bool fullnameGiven = false; 
801     bool foundFile     = false;
802
803     if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
804     {
805 // std::cout << "JPR==================  * found, load all boxes " << std::endl;
806       int nbBssFiles;
807
808       std::stringstream* stream = new std::stringstream;
809       //if (upath.size()!=0) // avoid troubles for "*"
810       
811       if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
812       {
813 // std::cout << "JPR==================  absolute name, load all .bbs files " << std::endl;      
814         int nbFiles = Utilities::Explore(upath, false, Filenames);
815         nbBssFiles = 0;
816         for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
817         {
818 // std::cout << "JPR==================  iterate [" << *i << "]" << std::endl;
819            int lgr = (*i).size();
820            if (lgr < 5)
821               continue;  // ignore non .bbs file
822            if ((*i).substr(lgr-4, 4) != ".bbs")
823               continue;
824            /*
825            if (lgr > 10) // 10 -> '-appli.bbs'
826            {    
827            if ((*i).substr(lgr-10, 10) == "-appli.bbs")
828               continue;      // ignore  '-appli.bbs' files
829            }
830            */
831
832        (*stream) << "include " << *i << "\n";
833 //EED  InterpretFile(*i);
834
835            nbBssFiles++;
836         } // for vector
837                 if (nbBssFiles==0){
838            bbtkMessage("Interpreter",2,
839                        "WARNING : No '.bbs' file found in [" 
840                        << upath << "]" << std::endl);
841                 } else {
842             SwitchToStream(stream);
843                 }
844         return;
845       }  // if upath
846
847       std::string path;
848       std::vector<std::string>::iterator i;
849       std::string fullDirectoryName;
850       for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
851       {
852         path = *i;
853
854        // we *really* want '.' to be the current working directory
855         if (path == ".") {
856           char buf[2048]; // for getcwd
857           char * currentDir = getcwd(buf, 2048);
858           std::string cwd(currentDir);
859           path = currentDir;
860         } // if path
861
862         fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
863
864         // without last slash "\"
865         std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
866
867       // Check if library exists
868         if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
869         {
870         // The following is *NOT* a debug time message :
871         // It's a user intended message.
872         // Please don't remove it.
873               bbtkMessage("Interpreter",1,"   [" <<fullDirectoryName 
874                       <<"] : doesn't exist" <<std::endl);
875           continue;  // try next path
876         } // if IsDirectory
877         foundFile = true;
878
879         Filenames.clear();
880         int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
881
882         nbBssFiles = 0;
883         for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
884         {
885 // std::cout << "JPR==================  iterate [" << *i << "]" << std::endl;
886            int lgr = (*i).size();
887            if (lgr < 5)
888               continue;  // ignore non .bbs file
889            if ((*i).substr(lgr-4, 4) != ".bbs")
890               continue;
891            /*
892            if (lgr > 10) // 10 -> '-appli.bbs'
893            {    
894            if ((*i).substr(lgr-10, 10) == "-appli.bbs")
895               continue;      // ignore  '-appli.bbs' files
896            }
897            */
898
899       (*stream) << "include " << *i << "\n";
900 //EED     InterpretFile(*i);
901
902            nbBssFiles++;
903         } // for vector
904                 if (nbBssFiles==0){
905            bbtkMessage("Interpreter",1,
906                       "WARNING : No '.bbs' file found in [" 
907                       << fullDirectoryName << "]" << std::endl);
908                 } else {
909            SwitchToStream(stream);
910                 }
911
912         //break; // a directory was found; we stop iterating
913         // LG : No! We want all files included !
914        } // for vector
915        return;
916     }  // if *
917
918     //std::string::size_type slash_position = name.find_last_of("/\\");
919
920     // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
921     // (not only a plain script name)
922     // we trust him, and try to expland the directory name
923     // WARNING : starting from current local directory :  ./whatYouWant  (./ mandatory!)
924
925     if (name[0]=='/' || name[1] == ':' || name[0]=='.')  // absolute path (linux/windows) or relative path
926     { 
927
928       // ===========================================================check user supplied location
929       fullnameGiven = true;
930
931       fullPathScriptName =  Utilities::ExpandLibName(name, false);
932
933       // allow user to always forget ".bbs"
934       int l = fullPathScriptName.size();
935
936       if (l!=0) {
937
938       if (l>4)
939       {
940          if (fullPathScriptName.substr(l-4, 4) != ".bbs")
941          {
942             fullPathScriptName = fullPathScriptName + ".bbs";
943          }
944       }
945       else
946       {
947          fullPathScriptName = fullPathScriptName + ".bbs";   
948       }
949
950       if ( Utilities::FileExists(fullPathScriptName))
951       {
952         foundFile = true;
953       }
954     } // endif l != 0
955   }
956   else
957       // =============================================================== iterate on the paths
958   {
959       std::string path;
960       std::vector<std::string>::iterator i;
961       for (i=script_paths.begin();i!=script_paths.end();++i)
962       {
963         path = *i;
964        // we *really* want '.' to be the current working directory
965         if (path == ".") {
966           char buf[2048]; // for getcwd
967           char * currentDir = getcwd(buf, 2048);
968           std::string cwd(currentDir);
969           path = currentDir;
970         }
971
972        fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
973
974       // Check if library exists
975         if ( ! Utilities::FileExists(fullPathScriptName) )
976         {
977         // The following is *NOT* a debug time message :
978         // It's a user intended message.
979         // Please don't remove it.
980               bbtkMessage("Interpreter",2,
981                       "   [" <<fullPathScriptName <<"] : doesn't exist" 
982                       <<std::endl);
983           continue;  // try next path
984         }
985             bbtkMessage("Interpreter",2,
986                     "   [" <<fullPathScriptName 
987                     <<"] : found" <<std::endl);
988         foundFile = true;
989         break; // a script was found; we stop iterating
990
991       } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
992     }
993
994     if (!foundFile)
995     {
996        if (fullnameGiven)
997          if(fullPathScriptName == "")
998             bbtkError("Path ["<<upath<<"] doesn't exist");
999          else
1000             bbtkError("Script ["<<fullPathScriptName<<"] not found");
1001        else
1002           bbtkError("No ["<<pkgname<<".bbs] script found");
1003        return;
1004     }
1005     else
1006       LoadScript(fullPathScriptName,name);
1007
1008     return;
1009   }
1010
1011
1012 void Interpreter::SwitchToStream( std::stringstream* stream )
1013 {
1014 //std::cout << "== 1 Entry in Interpreter::SwitchToStream " << std::endl;
1015
1016         mFile.push_back(stream);
1017     //std::cout << " mFile.size() " << mFile.size() << std::endl;
1018     std::ostringstream buffer_name;
1019     bufferNb++;
1020     buffer_name << "buffer_" ; // << bufferNb;
1021     
1022 //    std::cout << " mFile.size() "     << mFile.size() << std::endl;
1023 //    std::cout << " mFileName.size() " << mFileName.size() << std::endl;
1024 //    std::cout << " mLine.size() "     << mLine.size() << std::endl;
1025    // std::vector<std::string>::iterator j = mFileName.begin();
1026    //    std::cout << "  mFileName.begin() succeeded"  << std::endl;
1027    //    std::cout << "  mFileName[0] " <<   mFileName[0] << std::endl;
1028        //std::cout << "  mFileName.begin() " <<   mFileName.begin() << std::endl;
1029 /*
1030     for( std::vector<std::string>::iterator i = mFileName.begin(); i!= mFileName.end(); ++i)
1031     {
1032
1033        std::cout <<   "Interpreter::SwitchToStream : mFileName [" <<  *i << "]" << std::endl;
1034     }
1035 */
1036   //  std::cout << " mLine.back() " << mLine.back() << std::endl;
1037    // std::cout << " mFileName.back() " <<  mFileName.back() << std::endl;
1038
1039     if (mFileName.size()>0 )// && (mFile.size()>0) )  // NO!!!
1040     {
1041    // std::cout << "  mFileName.back() " <<  mFileName.back() << std::endl;
1042    // std::cout << "  mLine.back() " <<  mLine.back() << std::endl;
1043        buffer_name << mFileName.back() << "_" << mLine.back();
1044     }
1045 //std::cout << "3 in Interpreter::SwitchToStream buffer_name :[" << buffer_name.str() << "]" << std::endl;
1046     mFileName.push_back(buffer_name.str());
1047     mIncludeFileName.push_back(buffer_name.str());
1048     mLine.push_back(0);
1049 }
1050
1051   //=======================================================================
1052
1053   void Interpreter::LoadScript( std::string fullPathScriptName,
1054                                 std::string includeScriptName)
1055   {
1056      Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1057
1058      bool okScriptExist=false;
1059      int iStrScript,sizeVecStricpt=mFileName.size();
1060      for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1061      {
1062         if (mFileName[iStrScript] == fullPathScriptName )
1063         {
1064            okScriptExist=true;
1065         } // if
1066      } // for
1067
1068      if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1069 //    if (okScriptExist==true)
1070      {
1071             bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1072                     <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1073         return;
1074      }
1075
1076     std::ifstream* s;
1077     s = new std::ifstream;
1078     s->open(fullPathScriptName.c_str());
1079     if (!s->good())
1080     {
1081         bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1082         return;
1083     }
1084
1085     bbtkMessage("Interpreter",1,"   -->[" << fullPathScriptName 
1086                 << "] found" << std::endl);
1087
1088     mFile.push_back(s);
1089     mFileName.push_back(fullPathScriptName);
1090     mIncludeFileName.push_back(includeScriptName);
1091     mLine.push_back(0);
1092     return;
1093   }
1094
1095   //=======================================================================
1096   /**
1097    *  
1098    */
1099   void Interpreter::CloseCurrentFile()
1100   {
1101     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1102                       <<std::endl);
1103
1104     if (mFile.size()==0)
1105     {
1106       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1107       return;
1108     }
1109
1110     bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1111
1112     std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1113     if (file!=0) file->close();
1114
1115     delete mFile.back();
1116     mFile.pop_back();
1117     mFileName.pop_back();
1118     mIncludeFileName.pop_back();
1119     mLine.pop_back();
1120
1121     bbtkDebugMessage("Interpreter",9," Remains "
1122                      <<mFile.size()
1123                      <<" open"<<std::endl);
1124     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1125                      <<std::endl);
1126   }
1127   //=======================================================================
1128
1129  //=======================================================================
1130   /**
1131    *  
1132    */
1133   void Interpreter::CloseAllFiles()
1134   {
1135     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1136                       <<std::endl);
1137
1138     while (mFile.size() != 0) 
1139     {
1140        CloseCurrentFile();
1141     /*
1142       mFile.back()->close();
1143       delete mFile.back();
1144       mFile.pop_back();
1145       bbtkDebugMessage("Interpreter",9,
1146                       " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1147       mFileName.pop_back();
1148       mIncludeFileName.pop_back();
1149       mLine.pop_back();
1150 */
1151     }
1152     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1153                       <<std::endl);
1154   }
1155   //=======================================================================
1156
1157
1158
1159   //=======================================================================
1160   /**
1161    *  
1162    */
1163   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1164                                       CommandInfoType& info )
1165   {
1166     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1167
1168     // searches the command category
1169     CommandDictType::iterator c;
1170     c = mCommandDict.find(words[0]);
1171     if ( c == mCommandDict.end() ) {
1172       bbtkError(words[0]<<" : unknown command");
1173     }
1174
1175     // tests the number of args 
1176     if ( ( words.size()-1 < c->second.argmin ) ||
1177          ( words.size()-1 > c->second.argmax ) )
1178     {
1179        HelpCommand(words[0]);
1180        bbtkError(words[0]<<" : wrong number of arguments");
1181     }
1182
1183     info = c->second;
1184     bbtkDecTab("Interpreter",9);
1185   }
1186   //=======================================================================
1187
1188
1189   //=======================================================================
1190   /// Displays help on all the commands
1191 void Interpreter::Help(const std::vector<std::string>& words)
1192 {
1193     unsigned int nbarg = words.size()-1;
1194
1195     if (nbarg==0) 
1196     {
1197        HelpCommands();
1198     }
1199     else if (nbarg==1) 
1200     {
1201       if (words[1]=="packages") 
1202       {
1203          GetExecuter()->GetFactory()->PrintPackages(true);
1204          return;
1205       }
1206       try 
1207       {
1208           HelpCommand(words[1]);
1209       }
1210       catch (bbtk::Exception e) 
1211       {
1212          try 
1213          {
1214             GetExecuter()->GetFactory()->HelpPackage(words[1]);
1215 #ifdef _USE_WXWIDGETS_
1216             if ( mWxConsole != 0 )
1217               {
1218                 std::string url = 
1219                   ConfigurationFile::GetInstance().Get_doc_path();
1220                 url += "/bbdoc/" + words[1] + "/index.html";
1221                 if (Utilities::FileExists(url)) 
1222                   {
1223                     mWxConsole->ShowHtmlPage(url);
1224                   }
1225               }
1226 #endif      
1227          }
1228          catch (bbtk::Exception f) 
1229          {
1230             try 
1231             {
1232               std::string package;
1233               GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1234 #ifdef _USE_WXWIDGETS_
1235                if ( mWxConsole != 0 )
1236                  {
1237                    std::string url = 
1238                      ConfigurationFile::GetInstance().Get_doc_path();
1239                    url += "/bbdoc/" + package + "/index.html";
1240                    if (Utilities::FileExists(url))
1241                      {
1242                        url += "#" + words[1];
1243                        mWxConsole->ShowHtmlPage(url);
1244                      }
1245                  }
1246 #endif
1247             }
1248             catch (bbtk::Exception g) 
1249               {
1250                 try
1251                   {
1252                     GetExecuter()->ShowRelations(words[1],"0","9999");
1253                   }
1254                 catch (bbtk::Exception h){
1255                   bbtkError("\""<<words[1].c_str()
1256                             <<"\" is not a known command, package, black box type or black box name");
1257                 }
1258               }
1259          }
1260       }
1261     }
1262     else if (nbarg==2) 
1263     {
1264       if (words[2]=="all")
1265       {
1266          if ( words[1]=="packages" )
1267          {
1268             GetExecuter()->GetFactory()->PrintPackages(true,true);
1269             return;
1270           }
1271          try 
1272          {
1273             GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1274          }
1275          catch (bbtk::Exception f) 
1276          {
1277          }
1278      }
1279      else 
1280      {
1281         HelpCommand(words[0]);
1282         bbtkError(words[0]<<" : syntax error");
1283      }
1284   }
1285   else 
1286   {
1287      bbtkError("Should not reach here !!!");
1288   }
1289 }
1290   //=======================================================================
1291
1292    //===================================================================    
1293   /// Displays the Configuration
1294   void Interpreter::Config() const
1295   {
1296     ConfigurationFile::GetInstance().GetHelp(1);
1297   }  
1298    //===================================================================    
1299
1300   //=======================================================================
1301   /// Displays help on all the commands
1302   void Interpreter::HelpCommands()
1303   {
1304     std::cout << "Available commands :" << std::endl;
1305     CommandDictType::iterator i;
1306     for ( i =  mCommandDict.begin();
1307           i != mCommandDict.end();
1308         ++i) {
1309               std::cout << " " << i->first << std::endl;
1310       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1311       //     std::cout << "    " << i->second.help << std::endl;
1312
1313     }
1314   }
1315   //=======================================================================
1316
1317
1318   //=======================================================================
1319   /// Displays help on a particular commands
1320   void Interpreter::HelpCommand(const std::string& s)
1321   {
1322     CommandDictType::iterator c;
1323     c = mCommandDict.find(s);
1324     if ( c == mCommandDict.end() ) {
1325       bbtkError(s<<" : Unknown command");
1326     }
1327     //    std::cout << " " << s << " : "<<  std::endl;
1328     //    CommandParamDictType::iterator i;
1329     //    for ( i =  c->second.begin();
1330     //      i != c->second.end();
1331     //      ++i) {
1332     std::cout << " usage : " << c->second.syntax << std::endl;
1333     std::cout << "  " << c->second.help << std::endl;
1334
1335   }
1336   //=======================================================================
1337
1338
1339   //=======================================================================
1340   /// Fills the vector commands with the commands which 
1341   /// have the first n chars of buf for prefix
1342   /// TODO : skip initial spaces in buf and also return the position of first
1343   /// non blank char in buf
1344   void Interpreter::FindCommandsWithPrefix( char* buf,
1345                                             int n,
1346                                             std::vector<std::string>& commands )
1347   {
1348     CommandDictType::const_iterator i;
1349     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1350     {
1351       if ((i->first).find(buf,0,n) == 0) 
1352         commands.push_back(i->first);
1353     }
1354   }
1355   //=======================================================================
1356
1357
1358
1359   //=======================================================================
1360 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1361   
1362   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1363   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1364   
1365   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1366   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1367   // E.G. STORE THIS IN bbtk_config.xml
1368 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1369 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1370 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1371 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1372 #define BBTK_BACKSPACE_KBCODE   0x00000008
1373 #define BBTK_DEL_KBCODE         0x0000007F
1374 #define BBTK_SPACE_KBCODE       0x00000020 
1375
1376   //=======================================================================
1377   void Interpreter::GetLineFromPrompt(std::string& s)
1378   {
1379     int c;
1380     int ind=0;
1381
1382     int MAX_LINE_SIZE = 160;
1383     int MAX_HISTORY_SIZE = 100;
1384
1385     char* newline = new char[MAX_LINE_SIZE];
1386     memset(newline,0,MAX_LINE_SIZE);
1387     char* histline = new char[MAX_LINE_SIZE];
1388     memset(histline,0,MAX_LINE_SIZE);
1389
1390     char* line = newline;
1391     int hist = mHistory.size();
1392
1393     write(1,"> ",2);
1394     while(1)
1395     {
1396        c=0;
1397        read ( STDIN_FILENO, &c, 4) ;
1398
1399        bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1400
1401        // Printable character
1402        if ( (ind<MAX_LINE_SIZE-1) &&
1403             ( c >= BBTK_SPACE_KBCODE ) && 
1404             ( c <  BBTK_DEL_KBCODE )) 
1405        {
1406           PrintChar(c);
1407           line[ind++]=c;
1408        }
1409       // CR
1410        else if (c=='\n')
1411        {
1412        // delete the unused line
1413           if (line==newline)
1414               delete histline;
1415           else
1416               delete newline;
1417    
1418     // empty lines are not stored in from history
1419           if (strlen(line)) 
1420           {
1421              // if history too long : delete oldest command
1422              if (mHistory.size()>MAX_HISTORY_SIZE) 
1423              {
1424                 delete mHistory.front();
1425                 mHistory.pop_front();
1426              }
1427              mHistory.push_back(line);
1428           }
1429           break;
1430         }
1431        // Backspace
1432         else if ( (ind>0) && 
1433                   ((c == BBTK_BACKSPACE_KBCODE) ||
1434                    (c == BBTK_DEL_KBCODE)) )
1435           {
1436             line[ind--]=' ';
1437             BackSpace();
1438           }
1439         // Tab 
1440         else if (c=='\t')
1441           {
1442             // TODO : Command completion  
1443             std::vector<std::string> commands;
1444             FindCommandsWithPrefix( line,ind,commands);
1445             if (commands.size()==1) 
1446               {
1447                 std::string com = *commands.begin();
1448                 for (; ind<com.size(); ++ind) 
1449                   {
1450                     PrintChar(com[ind]); 
1451                     line[ind]=com[ind];
1452                   }
1453                 PrintChar(' '); 
1454                 line[ind++]=' ';
1455               }
1456             else if (commands.size()>1) 
1457               {
1458                 std::vector<std::string>::iterator i;
1459                 write(1,"\n",1);
1460                 for (i=commands.begin();i!=commands.end();++i) 
1461                   {
1462                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1463                     PrintChar(' ');
1464                   }
1465                 write(STDOUT_FILENO,"\n> ",3);
1466                 //for (int j=0;j<ind;++j) 
1467                   //{
1468                     write(STDOUT_FILENO,line,ind); 
1469                     //  }
1470               }
1471           }
1472         // Arrow up : back in history
1473         else if (c==BBTK_UP_ARROW_KBCODE)
1474           {
1475             if (hist) 
1476               {
1477                 // erase current line
1478                 while (ind--) BackSpace();
1479                 // 
1480                 hist--;
1481                 // 
1482                 strcpy(histline,mHistory[hist]);
1483                 line = histline;
1484                 ind = strlen(line);
1485                 
1486                 write(STDOUT_FILENO,line,ind);
1487               }
1488           }
1489         // Arrow down : down in history
1490         else if (c==BBTK_DOWN_ARROW_KBCODE)
1491           {
1492             if (hist<mHistory.size()-1) 
1493               {
1494                 // erase current line
1495                 while (ind--) BackSpace();
1496                 // 
1497                 hist++;
1498                 // 
1499                 strcpy(histline,mHistory[hist]);
1500                 line = histline;
1501                 ind = strlen(line);
1502                 
1503                 write(STDOUT_FILENO,line,ind);
1504               }
1505             // end of history : switch back to newline
1506             else if (hist==mHistory.size()-1)
1507               {
1508                 // erase current line
1509                 while (ind--) BackSpace();
1510                 // 
1511                 hist++;
1512                 // 
1513                 line = newline;
1514                 ind = strlen(line);
1515                 
1516                 write(STDOUT_FILENO,line,ind);
1517               }
1518           }
1519         // Arrow right
1520         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1521           {
1522             PrintChar(line[ind]);
1523             ind++;
1524           }
1525
1526         // Arrow left
1527         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1528           {
1529             PrintChar('\b');
1530             ind--;
1531     
1532           }
1533
1534       }
1535     write(STDOUT_FILENO,"\n\r",2);
1536     
1537     
1538     s = line;
1539     
1540   }
1541 #else
1542
1543   //=======================================================================
1544   void Interpreter::GetLineFromPrompt(std::string& s)
1545   {  
1546     s.clear();
1547
1548     putchar('>');
1549     putchar(' ');
1550
1551     do 
1552     {
1553       char c = getchar();
1554       if (c=='\n') 
1555       {
1556         putchar('\n');
1557         break;
1558       }
1559       if (c=='\t') 
1560       {
1561         // putchar('T');
1562         continue;
1563       }
1564       // putchar(c);
1565       s += c;
1566     } 
1567     while (true);  
1568     
1569   }
1570   //=======================================================================  
1571
1572 #endif
1573
1574
1575
1576   //=======================================================================
1577   void Interpreter::CommandLineInterpreter()
1578   {
1579     bbtkDebugMessageInc("Interpreter",9,
1580                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1581
1582 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1583     // Initialise the tty in non canonical mode with no echo
1584     // oter remembers the previous settings to restore them after 
1585     struct termios ter,oter;
1586     tcgetattr(0,&ter);
1587     oter=ter;
1588     ter.c_lflag &= ~ECHO;
1589     ter.c_lflag &= ~ICANON;
1590     ter.c_cc[VMIN]=1;
1591     ter.c_cc[VTIME]=0;
1592     tcsetattr(0,TCSANOW,&ter);
1593 #endif
1594     
1595     mCommandLine = true;
1596     bool again = true;
1597     bool insideComment = false; // for multiline comment  
1598     do 
1599     {
1600       try
1601       {
1602         std::string line;
1603         GetLineFromPrompt(line);
1604         InterpretLine(line, insideComment);
1605       }
1606       catch (QuitException e)
1607       {
1608         again = false;
1609       }
1610       catch (bbtk::Exception e) 
1611       {
1612         e.Print();
1613       }
1614         catch (std::exception& e) 
1615       {
1616         std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1617       }
1618       catch (...)
1619       {
1620         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1621       }
1622     }
1623     while (again);
1624
1625 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1626     tcsetattr(0,TCSANOW,&oter);
1627 #endif
1628
1629     std::cout << "Good bye !" << std::endl;
1630
1631     bbtkDebugDecTab("Interpreter",9);
1632   }
1633
1634 //=======================================================================
1635 void Interpreter::Graph(const std::vector<std::string>& words)
1636 {
1637   std::string page;
1638     bool system_display = true;
1639
1640 #ifdef _USE_WXWIDGETS_
1641     if ( mWxConsole != 0 ) system_display = false; 
1642 #endif
1643  
1644     if (words.size()==1) 
1645     {
1646       page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1647     }
1648     else if (words.size()==2) 
1649     {
1650       page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1651     }
1652     else if (words.size()==3) 
1653     {
1654       page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1655     }
1656     else if (words.size()==4) 
1657     {
1658       page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1659     } 
1660     else if (words.size()==5) 
1661     {
1662       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1663     } 
1664     else if (words.size()==6) 
1665     {
1666       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1667     } 
1668     else if (words.size()==7) 
1669       {
1670         page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1671       } 
1672     
1673 #ifdef _USE_WXWIDGETS_
1674     if ( mWxConsole != 0 )
1675       mWxConsole->ShowHtmlPage(page);
1676 #endif
1677   }
1678 //=======================================================================
1679
1680
1681 //=======================================================================
1682 void  Interpreter::Index(const std::string& filename, 
1683                          const std::string& type)
1684 {
1685   Factory::IndexEntryType t;
1686   if (type=="Initials") t = Factory::Initials;
1687   else if (type=="Categories") t = Factory::Categories;
1688   else if (type=="Packages") t = Factory::Packages;
1689   else if (type=="Adaptors") t = Factory::Adaptors;
1690   
1691   GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1692 }
1693 //=======================================================================
1694
1695 }//namespace
1696
1697