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