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