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