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