]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
e4d872b48847931b92969197fafa8b179462c350
[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/26 08:27:19 $
7   Version:   $Revision: 1.55 $
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         mExecuter->Destroy(words[1]);
659         break;
660
661       case cConnect :
662         Utilities::SplitAroundFirstDot(words[1],left,right);
663         Utilities::SplitAroundFirstDot(words[2],left2,right2);      
664         mExecuter->Connect(left,right,left2,right2);
665         break;
666
667       case cPackage :
668         mExecuter->BeginPackage(words[1]);
669         break;
670
671       case cEndPackage :
672         mExecuter->EndPackage();
673         break;
674
675       case cDefine :
676         if (mFileName.size()>0) 
677         {
678           filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
679         }
680         if (words.size()==2) 
681         {
682            mExecuter->Define(words[1],"",filename);
683         }
684         else
685         {
686            mExecuter->Define(words[1],words[2],filename);
687         }
688         break;
689
690       case cEndDefine :
691         mExecuter->EndDefine();
692         break;
693
694       case cPrint :
695         mExecuter->Print(words[1]);
696         break;
697         
698       case cExec :
699         if (words[1]=="freeze") 
700           mExecuter->SetNoExecMode(true);
701         else if (words[1]=="unfreeze") 
702           mExecuter->SetNoExecMode(false);
703         else
704           mExecuter->Execute(words[1]);
705         break;
706
707       case cInput :
708         Utilities::SplitAroundFirstDot(words[2],left,right);
709         mExecuter->DefineInput(words[1],left,right,words[3]);
710         break;
711
712       case cOutput :
713         Utilities::SplitAroundFirstDot(words[2],left,right);
714         mExecuter->DefineOutput(words[1],left,right,words[3]);
715         break;
716
717       case cSet :
718         Utilities::SplitAroundFirstDot(words[1],left,right);
719         mExecuter->Set(left,right,words[2]);
720         break;
721
722       case cAuthor :
723         mExecuter->Author(words[1]);
724         break;
725
726       case cCategory :
727         mExecuter->Category(words[1]);
728         break;
729
730       case cIndex :
731         if (words.size()==1)
732              Index("tmp_index.html");
733         else if (words.size()==2)
734              Index(words[1]);
735         else if (words.size()==3)
736              Index(words[1],words[2]);
737         break;
738
739       case cDescription :
740         mExecuter->Description(words[1]);
741         break;
742
743       case cHelp :
744         Help(words);
745         break;
746
747       case cMessage : 
748         if (words.size()<3)
749         {
750           mExecuter->HelpMessages();
751         }
752         else
753         {
754           sscanf(words[2].c_str(),"%d",&level);
755           mExecuter->SetMessageLevel(words[1],level);
756         }
757         break;
758
759       case cGraph :
760         Graph(words);
761         break;
762
763       case cConfig :
764         Config();
765         break;
766
767       case cReset :  
768         this->mExecuter->Reset();
769         break;
770
771       case cInclude :
772         if (mCommandLine)
773         {
774            InterpretFile(words[1]); 
775         }
776         else
777         {
778             SwitchToFile(words[1]);
779         }
780         // if 'source' was given
781         if (words.size()==3) 
782           {
783             GetExecuter()->SetCurrentFileName(words[1]);
784           }
785         break;
786
787       case cLoad:
788         GetExecuter()->LoadPackage(words[1]);
789         break;
790
791       case cUnload:
792         GetExecuter()->UnLoadPackage(words[1]);
793         break;
794
795       case cQuit :
796         delete mExecuter;
797         throw QuitException();
798         break;
799         /* obsolete
800       case cWorkspace :
801         if (words.size() == 2) 
802         {
803            if (words[1]=="freeze")        mExecuter->SetNoExecMode(true);
804            else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
805         }
806         else
807         {
808            mExecuter->SetWorkspaceName(words[2]);
809         }
810         break;
811         */
812       default:
813         bbtkInternalError("should not reach here !!!");
814    }
815
816    bbtkDecTab("Interpreter",9);
817 }
818   //=======================================================================  
819
820
821
822
823
824   //=======================================================================
825   /**
826    *
827    */
828 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
829 {
830     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
831
832     std::string delimiters = "\"";
833     std::vector<std::string> quote;
834     Utilities::SplitString(str,delimiters,quote);
835
836     delimiters = " \t";
837     std::vector<std::string>::iterator i;
838     for (i=quote.begin(); i!=quote.end(); ) 
839     {
840        Utilities::SplitString(*i,delimiters,tokens);
841        ++i;
842        if (i!=quote.end()) 
843        {
844         //    bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
845           tokens.push_back(*i);
846           ++i;
847        }
848     }
849
850     for (i=tokens.begin(); i!=tokens.end(); ++i) 
851     {
852        bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
853     }
854     bbtkDebugMessageCont("Interpreter",9,std::endl);
855
856     bbtkDebugDecTab("Interpreter",9);
857  }
858   //=======================================================================
859
860
861  
862
863   //=======================================================================
864   /**
865    *
866    */
867   /*
868   void Interpreter::Print( const std::string& str)
869   {
870     if (mExecuter->GetNoExecMode()) return;
871
872     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
873
874  // TO DO :
875  // InterpretLine ("load std")
876  // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande 
877  // InterpretLine("new Print _P_") 
878  // InterpretLine("connect _C_.Out _P_.In")
879  // int num = 1
880  
881
882     std::vector<std::string> chains;
883     std::string delimiters("$");
884
885     // Skip delimiters at beginning.
886     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
887     bool is_text = true;
888     if (lastPos>0) is_text = false;
889
890     // Find first delimiter.
891     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
892
893     while (std::string::npos != pos || std::string::npos != lastPos)
894     {
895        if (is_text) 
896        {
897           // Found a text token, add it to the vector.
898           chains.push_back(str.substr(lastPos, pos - lastPos));
899  // std::string token = str.substr(lastPos, pos - lastPos)
900  // InterpretLine("set _C_.In%num% %token%")
901  
902        }
903        else 
904        {
905
906        // is an output (between $$) : decode 
907          std::string tok,box,output;
908          tok = str.substr(lastPos, pos - lastPos);
909          Utilities::SplitAroundFirstDot(tok,box,output);
910          chains.push_back( mExecuter->Get(box,output) );
911
912 // InterpretLine("connect %tok% _C_.In%num%") 
913
914        }
915         // Skip delimiters.  Note the "not_of"
916        lastPos = str.find_first_not_of(delimiters, pos);
917         // Find next delimiter
918        pos = str.find_first_of(delimiters, lastPos);
919     //
920        is_text = !is_text;
921 // num ++;
922      }
923 // InterpretLine("exec _P_")
924 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
925
926      std::vector<std::string>::iterator i;
927      for (i= chains.begin(); i!=chains.end(); ++i) 
928      {
929        //  bbtkMessage("Echo",1,*i);
930        Utilities::SubsBackslashN(*i);
931        std::cout << *i;
932      }
933      std::cout << std::endl;
934      bbtkDebugDecTab("Interpreter",9);
935  }
936 */
937
938   //=======================================================================
939   /**
940    *
941    */
942
943 // ===================================================================================
944
945   void Interpreter::SwitchToFile( const std::string& name )
946   {
947   // Note : in the following :
948   // name : the user supplied name 
949   //      - abreviated name    e.g.       scr   scr.bbs
950   //      - relative full name e.g.       ./scr.bbs   ../../scr.bbs 
951   //      - absolute full name e.g.       /home/usrname/proj/dir/scr.bbs
952   //          same for Windows, with      c:, d: ...
953   //
954   // use ./directory/subdir/scrname.bbs
955   //
956
957     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
958                          <<name<<"\")"<<std::endl);
959
960     std::vector<std::string> script_paths;
961     std::string fullPathScriptName;  // full path script name
962     std::string pkgname;             // e.g. <scriptname>.bbs
963     std::vector<std::string> Filenames;
964
965     // The following is *NOT* a debug time message :
966     // It's a user intended message.
967     // Please don't remove it.
968     bbtkMessage("Interpreter",1,
969         "look for : [" << name
970         << "]" << std::endl);
971
972
973     std::string upath;
974     pkgname = Utilities::ExtractScriptName(name,upath);
975
976     bbtkMessage("Interpreter",1,
977                 "extract : pkgname [" << pkgname
978                  << "] upath [" << upath << "]" << std::endl);
979     bool fullnameGiven = false; 
980     bool foundFile     = false;
981
982     // ==== "*" provided : load all scripts in given path 
983     // relative (e.g. std/boxes/*) or absolute 
984     if (pkgname == "*") 
985       {
986         int nbBssFiles;
987         
988         std::stringstream* stream = new std::stringstream;
989         //if (upath.size()!=0) // avoid troubles for "*"
990         
991         // ==== no path provided : look in root bbs path
992         if (upath.size()==0)
993           {
994             //      bbtkMessage("Interpreter",1,
995             script_paths.push_back(  ConfigurationFile::GetInstance().Get_root_bbs_path() );
996           }
997         // ==== absolute path provided 
998         else if (upath[0]=='/' || upath[1] == ':' ) 
999           {
1000             script_paths.push_back(upath);
1001           }
1002         // ==== relative path provided : search all bbs path appended with 
1003         // the relative path provided
1004         else
1005           {    
1006              std::vector<std::string>::const_iterator i;
1007              for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1008                   i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1009                   i++)
1010                {
1011                  std::string full_path(*i);
1012                  full_path += ConfigurationFile::GetInstance().Get_file_separator();
1013                  full_path += upath;
1014                  script_paths.push_back(full_path);
1015                }
1016           } 
1017         // === search paths list complete : now explore it
1018         bbtkMessage("Interpreter",1,
1019                     "'*' provided. search paths : " << std::endl);
1020         /*
1021         int nbFiles = Utilities::Explore(upath, false, Filenames);
1022             nbBssFiles = 0;
1023             for (std::vector<std::string>::iterator i = Filenames.begin(); 
1024                  i!= Filenames.end(); ++i)
1025               {
1026                 int lgr = (*i).size();
1027                 if (lgr < 5)
1028                   continue;  // ignore non .bbs file
1029                 if ((*i).substr(lgr-4, 4) != ".bbs")
1030                   continue;
1031                 //printf("EED Interpreter::SwitchToFile flag01 %s \n", (*i).c_str() );
1032                 (*stream) << "include \"" << *i << "\"\n";
1033                 
1034                 nbBssFiles++;
1035               } // for vector
1036             if (nbBssFiles==0)
1037               {
1038                 bbtkMessage("Interpreter",2,
1039                             "WARNING : No '.bbs' file found in [" 
1040                             << upath << "]" << std::endl);
1041               } 
1042             else 
1043               {
1044                 SwitchToStream(stream);
1045               }
1046             return;
1047           }  // if upath
1048         */
1049         std::string path;
1050         std::vector<std::string>::iterator i;
1051         std::string fullDirectoryName;
1052         for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1053           {
1054             path = *i;
1055             
1056             bbtkMessage("Interpreter",1,
1057                         "----> '" << path << "'" << std::endl);
1058             // we *really* want '.' to be the current working directory
1059             if (path == ".") {
1060               char buf[2048]; // for getcwd
1061               char * currentDir = getcwd(buf, 2048);
1062               std::string cwd(currentDir);
1063               path = currentDir;
1064             } // if path
1065             
1066             fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
1067             
1068             // without last slash "\"
1069             std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
1070             
1071             // Check if directory exists
1072             if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
1073               {
1074                 // The following is *NOT* a debug time message :
1075                 // It's a user intended message.
1076                 // Please don't remove it.
1077                 bbtkMessage("Interpreter",1,"   [" <<fullDirectoryName 
1078                             <<"] : doesn't exist" <<std::endl);
1079                 continue;  // try next path
1080               } // if IsDirectory
1081             foundFile = true;
1082             
1083             Filenames.clear();
1084             int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
1085             
1086             nbBssFiles = 0;
1087             for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1088               {
1089                 int lgr = (*i).size();
1090                 if (lgr < 5)
1091                   continue;  // ignore non .bbs file
1092                 if ((*i).substr(lgr-4, 4) != ".bbs")
1093                   continue;
1094                 
1095                 //              printf("EED Interpreter::SwitchToFile flag02 %s \n", (*i).c_str() );
1096                 (*stream) << "include \"" << *i << "\"\n";
1097                 
1098                 nbBssFiles++;
1099               } // for vector
1100             if (nbBssFiles==0)
1101               {
1102                 bbtkMessage("Interpreter",1,
1103                             "WARNING : No '.bbs' file found in [" 
1104                             << fullDirectoryName << "]" << std::endl);
1105               } 
1106             else 
1107               {
1108                 SwitchToStream(stream);
1109               }
1110             
1111             //break; // a directory was found; we stop iterating
1112             // LG : No! We want all files included !
1113           } // for vector
1114         return;
1115       }  
1116     //=============== end pkgname=="*" ===========
1117
1118
1119     // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1120     // (not only a plain script name)
1121     // we trust him, and try to expland the directory name
1122     // WARNING : starting from current local directory :  ./whatYouWant  (./ mandatory!)
1123
1124     if (name[0]=='/' || name[1] == ':' || name[0]=='.')  // absolute path (linux/windows) or relative path
1125     { 
1126
1127       // ===========================================================check user supplied location
1128       fullnameGiven = true;
1129
1130       fullPathScriptName =  Utilities::ExpandLibName(name, false);
1131
1132       // allow user to always forget ".bbs"
1133       int l = fullPathScriptName.size();
1134
1135       if (l!=0) {
1136
1137       if (l>4)
1138       {
1139          if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1140          {
1141             fullPathScriptName = fullPathScriptName + ".bbs";
1142          }
1143       }
1144       else
1145       {
1146          fullPathScriptName = fullPathScriptName + ".bbs";   
1147       }
1148
1149       if ( Utilities::FileExists(fullPathScriptName))
1150       {
1151         foundFile = true;
1152       }
1153     } // endif l != 0
1154   }
1155   else
1156     // =============================== iterate on the paths
1157     {
1158       script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1159       std::string path;
1160       std::vector<std::string>::iterator i;
1161       for (i=script_paths.begin();i!=script_paths.end();++i)
1162         {
1163           path = *i;
1164           // we *really* want '.' to be the current working directory
1165           if (path == ".") {
1166             char buf[2048]; // for getcwd
1167             char * currentDir = getcwd(buf, 2048);
1168             std::string cwd(currentDir);
1169             path = currentDir;
1170           }
1171           
1172           fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1173           
1174           // Check if library exists
1175           if ( ! Utilities::FileExists(fullPathScriptName) )
1176             {
1177               // The following is *NOT* a debug time message :
1178               // It's a user intended message.
1179               // Please don't remove it.
1180               bbtkMessage("Interpreter",2,
1181                           "   [" <<fullPathScriptName <<"] : doesn't exist" 
1182                           <<std::endl);
1183               continue;  // try next path
1184             }
1185           bbtkMessage("Interpreter",2,
1186                       "   [" <<fullPathScriptName 
1187                       <<"] : found" <<std::endl);
1188           foundFile = true;
1189           break; // a script was found; we stop iterating
1190
1191         } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1192     }
1193     
1194     if (!foundFile)
1195       {
1196         if (fullnameGiven)
1197           if(fullPathScriptName == "")
1198             bbtkError("Path ["<<upath<<"] doesn't exist");
1199           else
1200             bbtkError("Script ["<<fullPathScriptName<<"] not found");
1201         else
1202           bbtkError("No ["<<pkgname<<".bbs] script found");
1203         return;
1204       }
1205     else
1206       LoadScript(fullPathScriptName,name);
1207     
1208     return;
1209   }
1210   //=======================================================================
1211
1212
1213   //=======================================================================
1214 void Interpreter::SwitchToStream( std::stringstream* stream )
1215 {
1216     mFile.push_back(stream);
1217     std::ostringstream buffer_name;
1218     bufferNb++;
1219     buffer_name << "buffer_" ;
1220
1221     if (mFileName.size()>0 )
1222     {
1223        buffer_name << mFileName.back() << "_" << mLine.back();
1224     }
1225     mFileName.push_back(buffer_name.str());
1226     mIncludeFileName.push_back(buffer_name.str());
1227     mLine.push_back(0);
1228 }
1229   //=======================================================================
1230
1231   //=======================================================================
1232
1233   void Interpreter::LoadScript( std::string fullPathScriptName,
1234                                 std::string includeScriptName)
1235   {
1236      Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1237
1238      bool okScriptExist=false;
1239      int iStrScript,sizeVecStricpt=mFileName.size();
1240      for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1241      {
1242         if (mFileName[iStrScript] == fullPathScriptName )
1243         {
1244            okScriptExist=true;
1245         } // if
1246      } // for
1247
1248      if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1249 //    if (okScriptExist==true)
1250      {
1251             bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1252                     <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1253         return;
1254      }
1255
1256     std::ifstream* s;
1257     s = new std::ifstream;
1258     s->open(fullPathScriptName.c_str());
1259     if (!s->good())
1260     {
1261         bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1262         return;
1263     }
1264
1265     bbtkMessage("Interpreter",1,"   -->[" << fullPathScriptName 
1266                 << "] found" << std::endl);
1267
1268     mFile.push_back(s);
1269     mFileName.push_back(fullPathScriptName);
1270     mIncludeFileName.push_back(includeScriptName);
1271     mLine.push_back(0);
1272
1273     return;
1274   }
1275
1276   //=======================================================================
1277   /**
1278    *  
1279    */
1280   void Interpreter::CloseCurrentFile()
1281   {
1282     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1283                       <<std::endl);
1284
1285     if (mFile.size()==0)
1286     {
1287       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1288       return;
1289     }
1290
1291     bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1292
1293     std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1294     if (file!=0) file->close();
1295
1296     delete mFile.back();
1297     mFile.pop_back();
1298     mFileName.pop_back();
1299     mIncludeFileName.pop_back();
1300     mLine.pop_back();
1301
1302     bbtkDebugMessage("Interpreter",9," Remains "
1303                      <<mFile.size()
1304                      <<" open"<<std::endl);
1305     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1306                      <<std::endl);
1307   }
1308   //=======================================================================
1309
1310  //=======================================================================
1311   /**
1312    *  
1313    */
1314   void Interpreter::CloseAllFiles()
1315   {
1316     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1317                       <<std::endl);
1318
1319     while (mFile.size() != 0) 
1320     {
1321        CloseCurrentFile();
1322     /*
1323       mFile.back()->close();
1324       delete mFile.back();
1325       mFile.pop_back();
1326       bbtkDebugMessage("Interpreter",9,
1327                       " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1328       mFileName.pop_back();
1329       mIncludeFileName.pop_back();
1330       mLine.pop_back();
1331 */
1332     }
1333     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1334                       <<std::endl);
1335   }
1336   //=======================================================================
1337
1338
1339
1340   //=======================================================================
1341   /**
1342    *  
1343    */
1344   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1345                                       CommandInfoType& info )
1346   {
1347     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1348
1349     // searches the command category
1350     CommandDictType::iterator c;
1351     c = mCommandDict.find(words[0]);
1352     if ( c == mCommandDict.end() ) {
1353       bbtkError(words[0]<<" : unknown command");
1354     }
1355
1356     // tests the number of args 
1357     if ( ( words.size()-1 < c->second.argmin ) ||
1358          ( words.size()-1 > c->second.argmax ) )
1359     {
1360        HelpCommand(words[0]);
1361        bbtkError(words[0]<<" : wrong number of arguments");
1362     }
1363
1364     info = c->second;
1365     bbtkDecTab("Interpreter",9);
1366   }
1367   //=======================================================================
1368
1369
1370   //=======================================================================
1371   /// Displays help on all the commands
1372 void Interpreter::Help(const std::vector<std::string>& words)
1373 {
1374     unsigned int nbarg = words.size()-1;
1375
1376     if (nbarg==0) 
1377     {
1378        HelpCommands();
1379     }
1380     else if (nbarg==1) 
1381     {
1382       if (words[1]=="packages") 
1383       {
1384          GetExecuter()->GetFactory()->PrintPackages(true);
1385          return;
1386       }
1387       try 
1388       {
1389           HelpCommand(words[1]);
1390       }
1391       catch (bbtk::Exception e) 
1392       {
1393          try 
1394          {
1395             GetExecuter()->GetFactory()->HelpPackage(words[1]);
1396             if ( mUser != 0 )
1397               {
1398                 std::string url = 
1399                   ConfigurationFile::GetInstance().Get_doc_path();
1400                 url += "/bbdoc/" + words[1] + "/index.html";
1401                 if (Utilities::FileExists(url)) 
1402                   {
1403                     mUser->InterpreterUserViewHtmlPage(url);
1404                   }
1405               }
1406          }
1407          catch (bbtk::Exception f) 
1408          {
1409            try 
1410              {
1411                std::string package;
1412                GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1413                if ( mUser != 0 )
1414                  {
1415                    std::string url = 
1416                      ConfigurationFile::GetInstance().Get_doc_path();
1417                    url += "/bbdoc/" + package + "/index.html";
1418                    if (Utilities::FileExists(url)) 
1419                      {
1420                        url += "#" + words[1];
1421                        mUser->InterpreterUserViewHtmlPage(url);
1422                      }
1423                  }
1424              }
1425            catch (bbtk::Exception g) 
1426              {
1427                try
1428                  {
1429                    GetExecuter()->ShowRelations(words[1],"0","9999");
1430                  }
1431                catch (bbtk::Exception h){
1432                  bbtkError("\""<<words[1].c_str()
1433                            <<"\" is not a known command, package, black box type or black box name");
1434                }
1435              }
1436          }
1437       }
1438     }
1439     else if (nbarg==2) 
1440     {
1441       if (words[2]=="all")
1442       {
1443          if ( words[1]=="packages" )
1444          {
1445             GetExecuter()->GetFactory()->PrintPackages(true,true);
1446             return;
1447           }
1448          try 
1449          {
1450             GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1451          }
1452          catch (bbtk::Exception f) 
1453          {
1454          }
1455      }
1456      else 
1457      {
1458         HelpCommand(words[0]);
1459         bbtkError(words[0]<<" : syntax error");
1460      }
1461   }
1462   else 
1463   {
1464      bbtkError("Should not reach here !!!");
1465   }
1466 }
1467   //=======================================================================
1468
1469    //===================================================================    
1470   /// Displays the Configuration
1471   void Interpreter::Config() const
1472   {
1473     ConfigurationFile::GetInstance().GetHelp(1);
1474   }  
1475    //===================================================================    
1476
1477   //=======================================================================
1478   /// Displays help on all the commands
1479   void Interpreter::HelpCommands()
1480   {
1481     std::cout << "Available commands :" << std::endl;
1482     CommandDictType::iterator i;
1483     for ( i =  mCommandDict.begin();
1484           i != mCommandDict.end();
1485         ++i) {
1486               std::cout << " " << i->first << std::endl;
1487       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1488       //     std::cout << "    " << i->second.help << std::endl;
1489
1490     }
1491   }
1492   //=======================================================================
1493
1494
1495   //=======================================================================
1496   /// Displays help on a particular commands
1497   void Interpreter::HelpCommand(const std::string& s)
1498   {
1499     CommandDictType::iterator c;
1500     c = mCommandDict.find(s);
1501     if ( c == mCommandDict.end() ) {
1502       bbtkError(s<<" : Unknown command");
1503     }
1504     //    std::cout << " " << s << " : "<<  std::endl;
1505     //    CommandParamDictType::iterator i;
1506     //    for ( i =  c->second.begin();
1507     //      i != c->second.end();
1508     //      ++i) {
1509     std::cout << " usage : " << c->second.syntax << std::endl;
1510     std::cout << "  " << c->second.help << std::endl;
1511
1512   }
1513   //=======================================================================
1514
1515
1516   //=======================================================================
1517   /// Fills the vector commands with the commands which 
1518   /// have the first n chars of buf for prefix
1519   /// TODO : skip initial spaces in buf and also return the position of first
1520   /// non blank char in buf
1521   void Interpreter::FindCommandsWithPrefix( char* buf,
1522                                             int n,
1523                                             std::vector<std::string>& commands )
1524   {
1525     CommandDictType::const_iterator i;
1526     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1527     {
1528       if ((i->first).find(buf,0,n) == 0) 
1529         commands.push_back(i->first);
1530     }
1531   }
1532   //=======================================================================
1533
1534
1535
1536   //=======================================================================
1537 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1538   
1539   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1540   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1541   
1542   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1543   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1544   // E.G. STORE THIS IN bbtk_config.xml
1545 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1546 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1547 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1548 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1549 #define BBTK_BACKSPACE_KBCODE   0x00000008
1550 #define BBTK_DEL_KBCODE         0x0000007F
1551 #define BBTK_SPACE_KBCODE       0x00000020 
1552
1553   //=======================================================================
1554   void Interpreter::GetLineFromPrompt(std::string& s)
1555   {
1556     int c;
1557     int ind=0;
1558
1559     int MAX_LINE_SIZE = 160;
1560     int MAX_HISTORY_SIZE = 100;
1561
1562     char* newline = new char[MAX_LINE_SIZE];
1563     memset(newline,0,MAX_LINE_SIZE);
1564     char* histline = new char[MAX_LINE_SIZE];
1565     memset(histline,0,MAX_LINE_SIZE);
1566
1567     char* line = newline;
1568     int hist = mHistory.size();
1569
1570     write(1,"> ",2);
1571     while(1)
1572     {
1573        c=0;
1574        read ( STDIN_FILENO, &c, 4) ;
1575
1576        bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1577
1578        // Printable character
1579        if ( (ind<MAX_LINE_SIZE-1) &&
1580             ( c >= BBTK_SPACE_KBCODE ) && 
1581             ( c <  BBTK_DEL_KBCODE )) 
1582        {
1583           PrintChar(c);
1584           line[ind++]=c;
1585        }
1586       // CR
1587        else if (c=='\n')
1588        {
1589        // delete the unused line
1590           if (line==newline)
1591               delete histline;
1592           else
1593               delete newline;
1594    
1595     // empty lines are not stored in from history
1596           if (strlen(line)) 
1597           {
1598              // if history too long : delete oldest command
1599              if (mHistory.size()>MAX_HISTORY_SIZE) 
1600              {
1601                 delete mHistory.front();
1602                 mHistory.pop_front();
1603              }
1604              mHistory.push_back(line);
1605           }
1606           break;
1607         }
1608        // Backspace
1609         else if ( (ind>0) && 
1610                   ((c == BBTK_BACKSPACE_KBCODE) ||
1611                    (c == BBTK_DEL_KBCODE)) )
1612           {
1613             line[ind--]=' ';
1614             BackSpace();
1615           }
1616         // Tab 
1617         else if (c=='\t')
1618           {
1619             // TODO : Command completion  
1620             std::vector<std::string> commands;
1621             FindCommandsWithPrefix( line,ind,commands);
1622             if (commands.size()==1) 
1623               {
1624                 std::string com = *commands.begin();
1625                 for (; ind<com.size(); ++ind) 
1626                   {
1627                     PrintChar(com[ind]); 
1628                     line[ind]=com[ind];
1629                   }
1630                 PrintChar(' '); 
1631                 line[ind++]=' ';
1632               }
1633             else if (commands.size()>1) 
1634               {
1635                 std::vector<std::string>::iterator i;
1636                 write(1,"\n",1);
1637                 for (i=commands.begin();i!=commands.end();++i) 
1638                   {
1639                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1640                     PrintChar(' ');
1641                   }
1642                 write(STDOUT_FILENO,"\n> ",3);
1643                 //for (int j=0;j<ind;++j) 
1644                   //{
1645                     write(STDOUT_FILENO,line,ind); 
1646                     //  }
1647               }
1648           }
1649         // Arrow up : back in history
1650         else if (c==BBTK_UP_ARROW_KBCODE)
1651           {
1652             if (hist) 
1653               {
1654                 // erase current line
1655                 while (ind--) BackSpace();
1656                 // 
1657                 hist--;
1658                 // 
1659                 strcpy(histline,mHistory[hist]);
1660                 line = histline;
1661                 ind = strlen(line);
1662                 
1663                 write(STDOUT_FILENO,line,ind);
1664               }
1665           }
1666         // Arrow down : down in history
1667         else if (c==BBTK_DOWN_ARROW_KBCODE)
1668           {
1669             if (hist<mHistory.size()-1) 
1670               {
1671                 // erase current line
1672                 while (ind--) BackSpace();
1673                 // 
1674                 hist++;
1675                 // 
1676                 strcpy(histline,mHistory[hist]);
1677                 line = histline;
1678                 ind = strlen(line);
1679                 
1680                 write(STDOUT_FILENO,line,ind);
1681               }
1682             // end of history : switch back to newline
1683             else if (hist==mHistory.size()-1)
1684               {
1685                 // erase current line
1686                 while (ind--) BackSpace();
1687                 // 
1688                 hist++;
1689                 // 
1690                 line = newline;
1691                 ind = strlen(line);
1692                 
1693                 write(STDOUT_FILENO,line,ind);
1694               }
1695           }
1696         // Arrow right
1697         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1698           {
1699             PrintChar(line[ind]);
1700             ind++;
1701           }
1702
1703         // Arrow left
1704         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1705           {
1706             PrintChar('\b');
1707             ind--;
1708     
1709           }
1710
1711       }
1712     write(STDOUT_FILENO,"\n\r",2);
1713     
1714     
1715     s = line;
1716     
1717   }
1718 #else
1719
1720   //=======================================================================
1721   void Interpreter::GetLineFromPrompt(std::string& s)
1722   {  
1723     s.clear();
1724
1725     putchar('>');
1726     putchar(' ');
1727
1728     do 
1729     {
1730       char c = getchar();
1731       if (c=='\n') 
1732       {
1733         putchar('\n');
1734         break;
1735       }
1736       if (c=='\t') 
1737       {
1738         // putchar('T');
1739         continue;
1740       }
1741       // putchar(c);
1742       s += c;
1743     } 
1744     while (true);  
1745     
1746   }
1747   //=======================================================================  
1748
1749 #endif
1750
1751
1752
1753   //=======================================================================
1754   void Interpreter::CommandLineInterpreter()
1755   {
1756     bbtkDebugMessageInc("Interpreter",9,
1757                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1758
1759 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1760     // Initialise the tty in non canonical mode with no echo
1761     // oter remembers the previous settings to restore them after 
1762     struct termios ter,oter;
1763     tcgetattr(0,&ter);
1764     oter=ter;
1765     ter.c_lflag &= ~ECHO;
1766     ter.c_lflag &= ~ICANON;
1767     ter.c_cc[VMIN]=1;
1768     ter.c_cc[VTIME]=0;
1769     tcsetattr(0,TCSANOW,&ter);
1770 #endif
1771     
1772     mCommandLine = true;
1773     bool again = true;
1774     bool insideComment = false; // for multiline comment  
1775     do 
1776     {
1777       try
1778       {
1779         std::string line;
1780         GetLineFromPrompt(line);
1781         InterpretLine(line, insideComment);
1782       }
1783       catch (QuitException e)
1784       {
1785         bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1786         again = false;
1787       }
1788       catch (bbtk::Exception e) 
1789       {
1790         e.Print();
1791       }
1792         catch (std::exception& e) 
1793       {
1794         std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1795       }
1796       catch (...)
1797       {
1798         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1799       }
1800     }
1801     while (again);
1802
1803 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1804     tcsetattr(0,TCSANOW,&oter);
1805 #endif
1806
1807     std::cout << "Good bye !" << std::endl;
1808
1809     bbtkDebugDecTab("Interpreter",9);
1810   }
1811
1812 //=======================================================================
1813 void Interpreter::Graph(const std::vector<std::string>& words)
1814 {
1815   std::string page;
1816     bool system_display = true;
1817
1818     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1819       system_display = false; 
1820  
1821     if (words.size()==1) 
1822     {
1823       page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1824     }
1825     else if (words.size()==2) 
1826     {
1827       page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1828     }
1829     else if (words.size()==3) 
1830     {
1831       page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1832     }
1833     else if (words.size()==4) 
1834     {
1835       page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1836     } 
1837     else if (words.size()==5) 
1838     {
1839       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1840     } 
1841     else if (words.size()==6) 
1842     {
1843       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1844     } 
1845     else if (words.size()==7) 
1846       {
1847         page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1848       } 
1849     
1850     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1851       mUser->InterpreterUserViewHtmlPage(page);
1852
1853   }
1854 //=======================================================================
1855
1856
1857 //=======================================================================
1858 void  Interpreter::Index(const std::string& filename, 
1859                          const std::string& type)
1860 {
1861   Factory::IndexEntryType t;
1862   if (type=="Initials") t = Factory::Initials;
1863   else if (type=="Categories") t = Factory::Categories;
1864   else if (type=="Packages") t = Factory::Packages;
1865   else if (type=="Adaptors") t = Factory::Adaptors;
1866   
1867   GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1868 }
1869 //=======================================================================
1870
1871 }//namespace
1872
1873