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