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