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