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