]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
*** empty log message ***
[bbtk.git] / kernel / src / bbtkInterpreter.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkInterpreter.cxx,v $ $
5   Language:  C++
6   Date:      $Date: 2008/03/26 08:51:43 $
7   Version:   $Revision: 1.56 $
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",3,
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             if ( Utilities::IsDirectory( upath ) )
1001               {
1002                 script_paths.push_back(upath);
1003               }
1004             else 
1005               {
1006                 bbtkError("'"<<upath<<"' : not a valid folder"); 
1007               }
1008           }
1009         // ==== relative path provided : search all bbs path appended with 
1010         // the relative path provided
1011         else
1012           {    
1013              std::vector<std::string>::const_iterator i;
1014              for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1015                   i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1016                   i++)
1017                {
1018                  std::string full_path(*i);
1019                  // we *really* want '.' to be the current working directory
1020                  if (full_path == ".") {
1021                    char buf[2048]; // for getcwd
1022                    char * currentDir = getcwd(buf, 2048);
1023                    std::string cwd(currentDir);
1024                    full_path = currentDir;
1025                  } // if full_path
1026             
1027                  full_path += ConfigurationFile::GetInstance().Get_file_separator();
1028                  full_path += upath;
1029
1030                  if ( Utilities::IsDirectory( full_path ) )
1031                    {
1032                      script_paths.push_back(full_path);
1033                    }
1034                } 
1035           }
1036         // === search paths list complete : now explore it
1037         if (script_paths.empty())
1038           {
1039             bbtkMessage("Interpreter",1,
1040                         "'"<<upath<<"' : No matching folder" << std::endl);
1041           }
1042
1043
1044         std::vector<std::string>::iterator i;
1045         for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1046           {
1047             bbtkMessage("Interpreter",1,
1048                         "--> Looking in '" << *i << "'" << std::endl);
1049          
1050             
1051             Filenames.clear();
1052             int nbFiles = Utilities::Explore(*i, false, Filenames);
1053             
1054             nbBssFiles = 0;
1055             for (std::vector<std::string>::iterator j = Filenames.begin(); 
1056                  j!= Filenames.end(); ++j)
1057               {
1058                 int lgr = (*j).size();
1059                 if (lgr < 5)
1060                   continue;  // ignore non .bbs file
1061                 if ((*j).substr(lgr-4, 4) != ".bbs")
1062                   continue;
1063                 
1064                 (*stream) << "include \"" << *j << "\"\n";
1065                 bbtkMessage("Interpreter",2,
1066                             "  --> Found '" << *j << "'" << std::endl);
1067                 
1068                 nbBssFiles++;
1069               } // for vector
1070             
1071             if (nbBssFiles==0)
1072               {
1073                 bbtkMessage("Interpreter",1,
1074                             "  --> No .bbs found"<< std::endl);
1075               } 
1076             else 
1077               {
1078                 bbtkMessage("Interpreter",1,
1079                             "  --> "<<nbBssFiles<<" .bbs found"<< std::endl);
1080                 SwitchToStream(stream);
1081               }
1082             
1083             //break; // a directory was found; we stop iterating
1084             // LG : No! We want all files included !
1085           } // for vector
1086         return;
1087       }  
1088     //=============== end pkgname=="*" ===========
1089
1090
1091     // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1092     // (not only a plain script name)
1093     // we trust him, and try to expland the directory name
1094     // WARNING : starting from current local directory :  ./whatYouWant  (./ mandatory!)
1095
1096     if (name[0]=='/' || name[1] == ':' || name[0]=='.')  // absolute path (linux/windows) or relative path
1097     { 
1098
1099       // ===========================================================check user supplied location
1100       fullnameGiven = true;
1101
1102       fullPathScriptName =  Utilities::ExpandLibName(name, false);
1103
1104       // allow user to always forget ".bbs"
1105       int l = fullPathScriptName.size();
1106
1107       if (l!=0) {
1108
1109       if (l>4)
1110       {
1111          if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1112          {
1113             fullPathScriptName = fullPathScriptName + ".bbs";
1114          }
1115       }
1116       else
1117       {
1118          fullPathScriptName = fullPathScriptName + ".bbs";   
1119       }
1120
1121       if ( Utilities::FileExists(fullPathScriptName))
1122       {
1123         foundFile = true;
1124       }
1125     } // endif l != 0
1126   }
1127   else
1128     // =============================== iterate on the paths
1129     {
1130       script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1131       std::string path;
1132       std::vector<std::string>::iterator i;
1133       for (i=script_paths.begin();i!=script_paths.end();++i)
1134         {
1135           path = *i;
1136           // we *really* want '.' to be the current working directory
1137           if (path == ".") {
1138             char buf[2048]; // for getcwd
1139             char * currentDir = getcwd(buf, 2048);
1140             std::string cwd(currentDir);
1141             path = currentDir;
1142           }
1143           
1144           fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1145           
1146           // Check if library exists
1147           if ( ! Utilities::FileExists(fullPathScriptName) )
1148             {
1149               // The following is *NOT* a debug time message :
1150               // It's a user intended message.
1151               // Please don't remove it.
1152               bbtkMessage("Interpreter",2,
1153                           "   [" <<fullPathScriptName <<"] : doesn't exist" 
1154                           <<std::endl);
1155               continue;  // try next path
1156             }
1157           bbtkMessage("Interpreter",2,
1158                       "   [" <<fullPathScriptName 
1159                       <<"] : found" <<std::endl);
1160           foundFile = true;
1161           break; // a script was found; we stop iterating
1162
1163         } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1164     }
1165     
1166     if (!foundFile)
1167       {
1168         if (fullnameGiven)
1169           if(fullPathScriptName == "")
1170             bbtkError("Path ["<<upath<<"] doesn't exist");
1171           else
1172             bbtkError("Script ["<<fullPathScriptName<<"] not found");
1173         else
1174           bbtkError("No ["<<pkgname<<".bbs] script found");
1175         return;
1176       }
1177     else
1178       LoadScript(fullPathScriptName,name);
1179     
1180     return;
1181   }
1182   //=======================================================================
1183
1184
1185   //=======================================================================
1186 void Interpreter::SwitchToStream( std::stringstream* stream )
1187 {
1188     mFile.push_back(stream);
1189     std::ostringstream buffer_name;
1190     bufferNb++;
1191     buffer_name << "buffer_" ;
1192
1193     if (mFileName.size()>0 )
1194     {
1195        buffer_name << mFileName.back() << "_" << mLine.back();
1196     }
1197     mFileName.push_back(buffer_name.str());
1198     mIncludeFileName.push_back(buffer_name.str());
1199     mLine.push_back(0);
1200 }
1201   //=======================================================================
1202
1203   //=======================================================================
1204
1205   void Interpreter::LoadScript( std::string fullPathScriptName,
1206                                 std::string includeScriptName)
1207   {
1208      Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1209
1210      bool okScriptExist=false;
1211      int iStrScript,sizeVecStricpt=mFileName.size();
1212      for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1213      {
1214         if (mFileName[iStrScript] == fullPathScriptName )
1215         {
1216            okScriptExist=true;
1217         } // if
1218      } // for
1219
1220      if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1221 //    if (okScriptExist==true)
1222      {
1223             bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1224                     <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1225         return;
1226      }
1227
1228     std::ifstream* s;
1229     s = new std::ifstream;
1230     s->open(fullPathScriptName.c_str());
1231     if (!s->good())
1232     {
1233         bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1234         return;
1235     }
1236
1237     bbtkMessage("Interpreter",1,"   -->[" << fullPathScriptName 
1238                 << "] found" << std::endl);
1239
1240     mFile.push_back(s);
1241     mFileName.push_back(fullPathScriptName);
1242     mIncludeFileName.push_back(includeScriptName);
1243     mLine.push_back(0);
1244
1245     return;
1246   }
1247
1248   //=======================================================================
1249   /**
1250    *  
1251    */
1252   void Interpreter::CloseCurrentFile()
1253   {
1254     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1255                       <<std::endl);
1256
1257     if (mFile.size()==0)
1258     {
1259       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1260       return;
1261     }
1262
1263     bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1264
1265     std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1266     if (file!=0) file->close();
1267
1268     delete mFile.back();
1269     mFile.pop_back();
1270     mFileName.pop_back();
1271     mIncludeFileName.pop_back();
1272     mLine.pop_back();
1273
1274     bbtkDebugMessage("Interpreter",9," Remains "
1275                      <<mFile.size()
1276                      <<" open"<<std::endl);
1277     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1278                      <<std::endl);
1279   }
1280   //=======================================================================
1281
1282  //=======================================================================
1283   /**
1284    *  
1285    */
1286   void Interpreter::CloseAllFiles()
1287   {
1288     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1289                       <<std::endl);
1290
1291     while (mFile.size() != 0) 
1292     {
1293        CloseCurrentFile();
1294     /*
1295       mFile.back()->close();
1296       delete mFile.back();
1297       mFile.pop_back();
1298       bbtkDebugMessage("Interpreter",9,
1299                       " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1300       mFileName.pop_back();
1301       mIncludeFileName.pop_back();
1302       mLine.pop_back();
1303 */
1304     }
1305     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1306                       <<std::endl);
1307   }
1308   //=======================================================================
1309
1310
1311
1312   //=======================================================================
1313   /**
1314    *  
1315    */
1316   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1317                                       CommandInfoType& info )
1318   {
1319     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1320
1321     // searches the command category
1322     CommandDictType::iterator c;
1323     c = mCommandDict.find(words[0]);
1324     if ( c == mCommandDict.end() ) {
1325       bbtkError(words[0]<<" : unknown command");
1326     }
1327
1328     // tests the number of args 
1329     if ( ( words.size()-1 < c->second.argmin ) ||
1330          ( words.size()-1 > c->second.argmax ) )
1331     {
1332        HelpCommand(words[0]);
1333        bbtkError(words[0]<<" : wrong number of arguments");
1334     }
1335
1336     info = c->second;
1337     bbtkDecTab("Interpreter",9);
1338   }
1339   //=======================================================================
1340
1341
1342   //=======================================================================
1343   /// Displays help on all the commands
1344 void Interpreter::Help(const std::vector<std::string>& words)
1345 {
1346     unsigned int nbarg = words.size()-1;
1347
1348     if (nbarg==0) 
1349     {
1350        HelpCommands();
1351     }
1352     else if (nbarg==1) 
1353     {
1354       if (words[1]=="packages") 
1355       {
1356          GetExecuter()->GetFactory()->PrintPackages(true);
1357          return;
1358       }
1359       try 
1360       {
1361           HelpCommand(words[1]);
1362       }
1363       catch (bbtk::Exception e) 
1364       {
1365          try 
1366          {
1367             GetExecuter()->GetFactory()->HelpPackage(words[1]);
1368             if ( mUser != 0 )
1369               {
1370                 std::string url = 
1371                   ConfigurationFile::GetInstance().Get_doc_path();
1372                 url += "/bbdoc/" + words[1] + "/index.html";
1373                 if (Utilities::FileExists(url)) 
1374                   {
1375                     mUser->InterpreterUserViewHtmlPage(url);
1376                   }
1377               }
1378          }
1379          catch (bbtk::Exception f) 
1380          {
1381            try 
1382              {
1383                std::string package;
1384                GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1385                if ( mUser != 0 )
1386                  {
1387                    std::string url = 
1388                      ConfigurationFile::GetInstance().Get_doc_path();
1389                    url += "/bbdoc/" + package + "/index.html";
1390                    if (Utilities::FileExists(url)) 
1391                      {
1392                        url += "#" + words[1];
1393                        mUser->InterpreterUserViewHtmlPage(url);
1394                      }
1395                  }
1396              }
1397            catch (bbtk::Exception g) 
1398              {
1399                try
1400                  {
1401                    GetExecuter()->ShowRelations(words[1],"0","9999");
1402                  }
1403                catch (bbtk::Exception h){
1404                  bbtkError("\""<<words[1].c_str()
1405                            <<"\" is not a known command, package, black box type or black box name");
1406                }
1407              }
1408          }
1409       }
1410     }
1411     else if (nbarg==2) 
1412     {
1413       if (words[2]=="all")
1414       {
1415          if ( words[1]=="packages" )
1416          {
1417             GetExecuter()->GetFactory()->PrintPackages(true,true);
1418             return;
1419           }
1420          try 
1421          {
1422             GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1423          }
1424          catch (bbtk::Exception f) 
1425          {
1426          }
1427      }
1428      else 
1429      {
1430         HelpCommand(words[0]);
1431         bbtkError(words[0]<<" : syntax error");
1432      }
1433   }
1434   else 
1435   {
1436      bbtkError("Should not reach here !!!");
1437   }
1438 }
1439   //=======================================================================
1440
1441    //===================================================================    
1442   /// Displays the Configuration
1443   void Interpreter::Config() const
1444   {
1445     ConfigurationFile::GetInstance().GetHelp(1);
1446   }  
1447    //===================================================================    
1448
1449   //=======================================================================
1450   /// Displays help on all the commands
1451   void Interpreter::HelpCommands()
1452   {
1453     std::cout << "Available commands :" << std::endl;
1454     CommandDictType::iterator i;
1455     for ( i =  mCommandDict.begin();
1456           i != mCommandDict.end();
1457         ++i) {
1458               std::cout << " " << i->first << std::endl;
1459       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1460       //     std::cout << "    " << i->second.help << std::endl;
1461
1462     }
1463   }
1464   //=======================================================================
1465
1466
1467   //=======================================================================
1468   /// Displays help on a particular commands
1469   void Interpreter::HelpCommand(const std::string& s)
1470   {
1471     CommandDictType::iterator c;
1472     c = mCommandDict.find(s);
1473     if ( c == mCommandDict.end() ) {
1474       bbtkError(s<<" : Unknown command");
1475     }
1476     //    std::cout << " " << s << " : "<<  std::endl;
1477     //    CommandParamDictType::iterator i;
1478     //    for ( i =  c->second.begin();
1479     //      i != c->second.end();
1480     //      ++i) {
1481     std::cout << " usage : " << c->second.syntax << std::endl;
1482     std::cout << "  " << c->second.help << std::endl;
1483
1484   }
1485   //=======================================================================
1486
1487
1488   //=======================================================================
1489   /// Fills the vector commands with the commands which 
1490   /// have the first n chars of buf for prefix
1491   /// TODO : skip initial spaces in buf and also return the position of first
1492   /// non blank char in buf
1493   void Interpreter::FindCommandsWithPrefix( char* buf,
1494                                             int n,
1495                                             std::vector<std::string>& commands )
1496   {
1497     CommandDictType::const_iterator i;
1498     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1499     {
1500       if ((i->first).find(buf,0,n) == 0) 
1501         commands.push_back(i->first);
1502     }
1503   }
1504   //=======================================================================
1505
1506
1507
1508   //=======================================================================
1509 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1510   
1511   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1512   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1513   
1514   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1515   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1516   // E.G. STORE THIS IN bbtk_config.xml
1517 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1518 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1519 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1520 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1521 #define BBTK_BACKSPACE_KBCODE   0x00000008
1522 #define BBTK_DEL_KBCODE         0x0000007F
1523 #define BBTK_SPACE_KBCODE       0x00000020 
1524
1525   //=======================================================================
1526   void Interpreter::GetLineFromPrompt(std::string& s)
1527   {
1528     int c;
1529     int ind=0;
1530
1531     int MAX_LINE_SIZE = 160;
1532     int MAX_HISTORY_SIZE = 100;
1533
1534     char* newline = new char[MAX_LINE_SIZE];
1535     memset(newline,0,MAX_LINE_SIZE);
1536     char* histline = new char[MAX_LINE_SIZE];
1537     memset(histline,0,MAX_LINE_SIZE);
1538
1539     char* line = newline;
1540     int hist = mHistory.size();
1541
1542     write(1,"> ",2);
1543     while(1)
1544     {
1545        c=0;
1546        read ( STDIN_FILENO, &c, 4) ;
1547
1548        bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1549
1550        // Printable character
1551        if ( (ind<MAX_LINE_SIZE-1) &&
1552             ( c >= BBTK_SPACE_KBCODE ) && 
1553             ( c <  BBTK_DEL_KBCODE )) 
1554        {
1555           PrintChar(c);
1556           line[ind++]=c;
1557        }
1558       // CR
1559        else if (c=='\n')
1560        {
1561        // delete the unused line
1562           if (line==newline)
1563               delete histline;
1564           else
1565               delete newline;
1566    
1567     // empty lines are not stored in from history
1568           if (strlen(line)) 
1569           {
1570              // if history too long : delete oldest command
1571              if (mHistory.size()>MAX_HISTORY_SIZE) 
1572              {
1573                 delete mHistory.front();
1574                 mHistory.pop_front();
1575              }
1576              mHistory.push_back(line);
1577           }
1578           break;
1579         }
1580        // Backspace
1581         else if ( (ind>0) && 
1582                   ((c == BBTK_BACKSPACE_KBCODE) ||
1583                    (c == BBTK_DEL_KBCODE)) )
1584           {
1585             line[ind--]=' ';
1586             BackSpace();
1587           }
1588         // Tab 
1589         else if (c=='\t')
1590           {
1591             // TODO : Command completion  
1592             std::vector<std::string> commands;
1593             FindCommandsWithPrefix( line,ind,commands);
1594             if (commands.size()==1) 
1595               {
1596                 std::string com = *commands.begin();
1597                 for (; ind<com.size(); ++ind) 
1598                   {
1599                     PrintChar(com[ind]); 
1600                     line[ind]=com[ind];
1601                   }
1602                 PrintChar(' '); 
1603                 line[ind++]=' ';
1604               }
1605             else if (commands.size()>1) 
1606               {
1607                 std::vector<std::string>::iterator i;
1608                 write(1,"\n",1);
1609                 for (i=commands.begin();i!=commands.end();++i) 
1610                   {
1611                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1612                     PrintChar(' ');
1613                   }
1614                 write(STDOUT_FILENO,"\n> ",3);
1615                 //for (int j=0;j<ind;++j) 
1616                   //{
1617                     write(STDOUT_FILENO,line,ind); 
1618                     //  }
1619               }
1620           }
1621         // Arrow up : back in history
1622         else if (c==BBTK_UP_ARROW_KBCODE)
1623           {
1624             if (hist) 
1625               {
1626                 // erase current line
1627                 while (ind--) BackSpace();
1628                 // 
1629                 hist--;
1630                 // 
1631                 strcpy(histline,mHistory[hist]);
1632                 line = histline;
1633                 ind = strlen(line);
1634                 
1635                 write(STDOUT_FILENO,line,ind);
1636               }
1637           }
1638         // Arrow down : down in history
1639         else if (c==BBTK_DOWN_ARROW_KBCODE)
1640           {
1641             if (hist<mHistory.size()-1) 
1642               {
1643                 // erase current line
1644                 while (ind--) BackSpace();
1645                 // 
1646                 hist++;
1647                 // 
1648                 strcpy(histline,mHistory[hist]);
1649                 line = histline;
1650                 ind = strlen(line);
1651                 
1652                 write(STDOUT_FILENO,line,ind);
1653               }
1654             // end of history : switch back to newline
1655             else if (hist==mHistory.size()-1)
1656               {
1657                 // erase current line
1658                 while (ind--) BackSpace();
1659                 // 
1660                 hist++;
1661                 // 
1662                 line = newline;
1663                 ind = strlen(line);
1664                 
1665                 write(STDOUT_FILENO,line,ind);
1666               }
1667           }
1668         // Arrow right
1669         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1670           {
1671             PrintChar(line[ind]);
1672             ind++;
1673           }
1674
1675         // Arrow left
1676         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1677           {
1678             PrintChar('\b');
1679             ind--;
1680     
1681           }
1682
1683       }
1684     write(STDOUT_FILENO,"\n\r",2);
1685     
1686     
1687     s = line;
1688     
1689   }
1690 #else
1691
1692   //=======================================================================
1693   void Interpreter::GetLineFromPrompt(std::string& s)
1694   {  
1695     s.clear();
1696
1697     putchar('>');
1698     putchar(' ');
1699
1700     do 
1701     {
1702       char c = getchar();
1703       if (c=='\n') 
1704       {
1705         putchar('\n');
1706         break;
1707       }
1708       if (c=='\t') 
1709       {
1710         // putchar('T');
1711         continue;
1712       }
1713       // putchar(c);
1714       s += c;
1715     } 
1716     while (true);  
1717     
1718   }
1719   //=======================================================================  
1720
1721 #endif
1722
1723
1724
1725   //=======================================================================
1726   void Interpreter::CommandLineInterpreter()
1727   {
1728     bbtkDebugMessageInc("Interpreter",9,
1729                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1730
1731 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1732     // Initialise the tty in non canonical mode with no echo
1733     // oter remembers the previous settings to restore them after 
1734     struct termios ter,oter;
1735     tcgetattr(0,&ter);
1736     oter=ter;
1737     ter.c_lflag &= ~ECHO;
1738     ter.c_lflag &= ~ICANON;
1739     ter.c_cc[VMIN]=1;
1740     ter.c_cc[VTIME]=0;
1741     tcsetattr(0,TCSANOW,&ter);
1742 #endif
1743     
1744     mCommandLine = true;
1745     bool again = true;
1746     bool insideComment = false; // for multiline comment  
1747     do 
1748     {
1749       try
1750       {
1751         std::string line;
1752         GetLineFromPrompt(line);
1753         InterpretLine(line, insideComment);
1754       }
1755       catch (QuitException e)
1756       {
1757         bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1758         again = false;
1759       }
1760       catch (bbtk::Exception e) 
1761       {
1762         e.Print();
1763       }
1764         catch (std::exception& e) 
1765       {
1766         std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1767       }
1768       catch (...)
1769       {
1770         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1771       }
1772     }
1773     while (again);
1774
1775 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1776     tcsetattr(0,TCSANOW,&oter);
1777 #endif
1778
1779     std::cout << "Good bye !" << std::endl;
1780
1781     bbtkDebugDecTab("Interpreter",9);
1782   }
1783
1784 //=======================================================================
1785 void Interpreter::Graph(const std::vector<std::string>& words)
1786 {
1787   std::string page;
1788     bool system_display = true;
1789
1790     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1791       system_display = false; 
1792  
1793     if (words.size()==1) 
1794     {
1795       page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1796     }
1797     else if (words.size()==2) 
1798     {
1799       page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1800     }
1801     else if (words.size()==3) 
1802     {
1803       page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1804     }
1805     else if (words.size()==4) 
1806     {
1807       page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1808     } 
1809     else if (words.size()==5) 
1810     {
1811       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1812     } 
1813     else if (words.size()==6) 
1814     {
1815       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1816     } 
1817     else if (words.size()==7) 
1818       {
1819         page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1820       } 
1821     
1822     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1823       mUser->InterpreterUserViewHtmlPage(page);
1824
1825   }
1826 //=======================================================================
1827
1828
1829 //=======================================================================
1830 void  Interpreter::Index(const std::string& filename, 
1831                          const std::string& type)
1832 {
1833   Factory::IndexEntryType t;
1834   if (type=="Initials") t = Factory::Initials;
1835   else if (type=="Categories") t = Factory::Categories;
1836   else if (type=="Packages") t = Factory::Packages;
1837   else if (type=="Adaptors") t = Factory::Adaptors;
1838   
1839   GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1840 }
1841 //=======================================================================
1842
1843 }//namespace
1844
1845