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