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