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