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