]> Creatis software - bbtk.git/blob - kernel/src/bbtkInterpreter.cxx
850784a8443909b112ddc4481cd87b8f7ed7e186
[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/22 08:29:09 $
7   Version:   $Revision: 1.62 $
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     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
583
584     ExitStatus status = Interpreter_OK;
585
586     try 
587     {
588       bool insideComment = false;
589       InterpretLine(line, insideComment);
590     }
591     CATCH_MACRO;
592     /*
593    catch (QuitException e) 
594       { 
595       status = Interpreter_QUIT;
596       }
597     catch (bbtk::Exception e) 
598       {
599         std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
600         status = Interpreter_ERROR;
601       }
602     catch (std::exception& e) 
603       {
604         std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
605         status = Interpreter_ERROR;
606     }  
607     catch (...)
608       {
609         std::cerr 
610           << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
611         status = Interpreter_ERROR;
612       }
613     */
614
615     bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
616                      <<std::endl);
617     bbtkDecTab("Interpreter",9);
618     
619     return status;
620   }
621   
622
623   //=======================================================================  
624   /**
625    *
626    */
627 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
628 {
629     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
630     bbtkMessage("Echo",2,line<<std::endl);
631
632     std::vector<std::string> words;
633     SplitLine(line,words);
634
635     // Empty line
636     if (words.size()<1) 
637     {
638        bbtkDebugDecTab("Interpreter",9);
639        return;
640     }
641
642     // Single line comment : # or //
643     if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') ) 
644     {  
645        bbtkDebugDecTab("Interpreter",9);
646        bbtkMessage("Interpreter",9,"Comment"<<std::endl);
647        return;
648     }
649
650     // Multi line comment ( /* ... */ ) -delimiters on different lines !-
651     
652     if (words[0][0]=='/' && words[0][1]=='*') 
653     {  
654        bbtkDebugDecTab("Interpreter",9);
655        bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
656        insideComment = true;
657        return;
658     }
659
660     if (words[0][0]=='*' && words[0][1]=='/') 
661     {  
662        bbtkDebugDecTab("Interpreter",9);
663        bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
664        if ( !insideComment ) {
665           bbtkDebugDecTab("Interpreter",9);
666           bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);       
667        }
668        insideComment = false;
669        return;
670     }
671
672     if (insideComment) 
673     {  
674        bbtkDebugDecTab("Interpreter",9);
675        bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
676        return;
677     }
678
679     // Command 
680     CommandInfoType command;
681     InterpretCommand(words,command);
682
683     bbtkDebugMessage("Interpreter",9,
684                      "Command='"<<command.keyword
685                       <<"' code="<<command.code<<std::endl); 
686     int level=0;
687     std::string left,right,left2,right2;
688     std::string filename;
689     switch (command.code) 
690     {
691       case cNew :
692         mExecuter->Create(words[1],words[2]);
693         break;
694
695       case cDelete :
696         mExecuter->Destroy(words[1]);
697         break;
698
699       case cConnect :
700         Utilities::SplitAroundFirstDot(words[1],left,right);
701         Utilities::SplitAroundFirstDot(words[2],left2,right2);      
702         mExecuter->Connect(left,right,left2,right2);
703         break;
704
705       case cPackage :
706         mExecuter->BeginPackage(words[1]);
707         break;
708
709       case cEndPackage :
710         mExecuter->EndPackage();
711         break;
712
713       case cDefine :
714         if (mFileName.size()>0) 
715         {
716           filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
717         }
718         if (words.size()==2) 
719         {
720            mExecuter->Define(words[1],"",filename);
721         }
722         else
723         {
724            mExecuter->Define(words[1],words[2],filename);
725         }
726         break;
727
728       case cEndDefine :
729         mExecuter->EndDefine();
730         break;
731
732       case cKind :
733         mExecuter->Kind(words[1]);
734         break;
735
736       case cPrint :
737         mExecuter->Print(words[1]);
738         break;
739         
740       case cExec :
741         if (words[1]=="freeze") 
742           mExecuter->SetNoExecMode(true);
743         else if (words[1]=="unfreeze") 
744           mExecuter->SetNoExecMode(false);
745         else
746           mExecuter->Execute(words[1]);
747         break;
748
749       case cInput :
750         Utilities::SplitAroundFirstDot(words[2],left,right);
751         mExecuter->DefineInput(words[1],left,right,words[3]);
752         break;
753
754       case cOutput :
755         Utilities::SplitAroundFirstDot(words[2],left,right);
756         mExecuter->DefineOutput(words[1],left,right,words[3]);
757         break;
758
759       case cSet :
760         Utilities::SplitAroundFirstDot(words[1],left,right);
761         mExecuter->Set(left,right,words[2]);
762         break;
763
764       case cAuthor :
765         mExecuter->Author(words[1]);
766         break;
767
768       case cNewGUI :
769         NewGUI(words[1],words[2]);
770         break;
771
772       case cCategory :
773         mExecuter->Category(words[1]);
774         break;
775
776       case cIndex :
777         if (words.size()==1)
778              Index("tmp_index.html");
779         else if (words.size()==2)
780              Index(words[1]);
781         else if (words.size()==3)
782              Index(words[1],words[2]);
783         break;
784
785       case cDescription :
786         mExecuter->Description(words[1]);
787         break;
788
789       case cHelp :
790         Help(words);
791         break;
792
793       case cMessage : 
794         if (words.size()<3)
795         {
796           mExecuter->HelpMessages();
797         }
798         else
799         {
800           sscanf(words[2].c_str(),"%d",&level);
801           mExecuter->SetMessageLevel(words[1],level);
802         }
803         break;
804
805       case cGraph :
806         Graph(words);
807         break;
808
809       case cConfig :
810         Config();
811         break;
812
813       case cReset :  
814         Reset();
815         break;
816
817       case cInclude :
818         if (mCommandLine)
819         {
820            InterpretFile(words[1]); 
821         }
822         else
823         {
824             SwitchToFile(words[1]);
825         }
826         // if 'source' was given
827         if (words.size()==3) 
828           {
829             GetExecuter()->SetCurrentFileName(words[1]);
830           }
831         break;
832
833       case cLoad:
834         GetExecuter()->LoadPackage(words[1]);
835         break;
836
837       case cUnload:
838         GetExecuter()->UnLoadPackage(words[1]);
839         break;
840
841       case cQuit :
842         throw QuitException();
843         break;
844
845       case cObject :
846         if (words.size()==2) ObjectInfo(words[1]);
847         else ObjectInfo("");
848         break;
849         /* obsolete
850       case cWorkspace :
851         if (words.size() == 2) 
852         {
853            if (words[1]=="freeze")        mExecuter->SetNoExecMode(true);
854            else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
855         }
856         else
857         {
858            mExecuter->SetWorkspaceName(words[2]);
859         }
860         break;
861         */
862       default:
863         bbtkInternalError("should not reach here !!!");
864    }
865
866    bbtkDecTab("Interpreter",9);
867 }
868   //=======================================================================  
869
870
871
872
873
874   //=======================================================================
875   /**
876    *
877    */
878 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
879 {
880     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
881
882     std::string delimiters = "\"";
883     std::vector<std::string> quote;
884     Utilities::SplitString(str,delimiters,quote);
885
886     delimiters = " \t";
887     std::vector<std::string>::iterator i;
888     for (i=quote.begin(); i!=quote.end(); ) 
889     {
890        Utilities::SplitString(*i,delimiters,tokens);
891        ++i;
892        if (i!=quote.end()) 
893        {
894         //    bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
895           tokens.push_back(*i);
896           ++i;
897        }
898     }
899
900     for (i=tokens.begin(); i!=tokens.end(); ++i) 
901     {
902        bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
903     }
904     bbtkDebugMessageCont("Interpreter",9,std::endl);
905
906     bbtkDebugDecTab("Interpreter",9);
907  }
908   //=======================================================================
909
910
911   //=======================================================================
912   void Interpreter::Reset()
913   {
914     // Cannot close all files if the reset command is read from a file !
915     //    CloseAllFiles();
916     mFileNameHistory.clear();
917     this->mExecuter->Reset();
918   }
919   //=======================================================================
920
921   //=======================================================================
922   /**
923    *
924    */
925   /*
926   void Interpreter::Print( const std::string& str)
927   {
928     if (mExecuter->GetNoExecMode()) return;
929
930     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
931
932  // TO DO :
933  // InterpretLine ("load std")
934  // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande 
935  // InterpretLine("new Print _P_") 
936  // InterpretLine("connect _C_.Out _P_.In")
937  // int num = 1
938  
939
940     std::vector<std::string> chains;
941     std::string delimiters("$");
942
943     // Skip delimiters at beginning.
944     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
945     bool is_text = true;
946     if (lastPos>0) is_text = false;
947
948     // Find first delimiter.
949     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
950
951     while (std::string::npos != pos || std::string::npos != lastPos)
952     {
953        if (is_text) 
954        {
955           // Found a text token, add it to the vector.
956           chains.push_back(str.substr(lastPos, pos - lastPos));
957  // std::string token = str.substr(lastPos, pos - lastPos)
958  // InterpretLine("set _C_.In%num% %token%")
959  
960        }
961        else 
962        {
963
964        // is an output (between $$) : decode 
965          std::string tok,box,output;
966          tok = str.substr(lastPos, pos - lastPos);
967          Utilities::SplitAroundFirstDot(tok,box,output);
968          chains.push_back( mExecuter->Get(box,output) );
969
970 // InterpretLine("connect %tok% _C_.In%num%") 
971
972        }
973         // Skip delimiters.  Note the "not_of"
974        lastPos = str.find_first_not_of(delimiters, pos);
975         // Find next delimiter
976        pos = str.find_first_of(delimiters, lastPos);
977     //
978        is_text = !is_text;
979 // num ++;
980      }
981 // InterpretLine("exec _P_")
982 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
983
984      std::vector<std::string>::iterator i;
985      for (i= chains.begin(); i!=chains.end(); ++i) 
986      {
987        //  bbtkMessage("Echo",1,*i);
988        Utilities::SubsBackslashN(*i);
989        std::cout << *i;
990      }
991      std::cout << std::endl;
992      bbtkDebugDecTab("Interpreter",9);
993  }
994 */
995
996   //=======================================================================
997   /**
998    *
999    */
1000
1001   // =========================================================================
1002   void Interpreter::SwitchToFile( const std::string& name )
1003   {
1004   // Note : in the following :
1005   // name : the user supplied name 
1006   //      - abreviated name    e.g.       scr   scr.bbs
1007   //      - relative full name e.g.       ./scr.bbs   ../../scr.bbs 
1008   //      - absolute full name e.g.       /home/usrname/proj/dir/scr.bbs
1009   //          same for Windows, with      c:, d: ...
1010   //
1011   // use ./directory/subdir/scrname.bbs
1012   //
1013
1014     bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
1015                          <<name<<"\")"<<std::endl);
1016
1017     std::vector<std::string> script_paths;
1018     std::string fullPathScriptName;  // full path script name
1019     std::string pkgname;             // e.g. <scriptname>.bbs
1020     std::vector<std::string> Filenames;
1021
1022     // The following is *NOT* a debug time message :
1023     // It's a user intended message.
1024     // Please don't remove it.
1025     bbtkMessage("Interpreter",1,
1026         "look for : [" << name
1027         << "]" << std::endl);
1028
1029
1030     std::string upath;
1031     pkgname = Utilities::ExtractScriptName(name,upath);
1032
1033     bbtkMessage("Interpreter",3,
1034                 "extract : pkgname [" << pkgname
1035                  << "] upath [" << upath << "]" << std::endl);
1036     bool fullnameGiven = false; 
1037     bool foundFile     = false;
1038
1039     // ==== "*" provided : load all scripts in given path 
1040     // relative (e.g. std/boxes/*) or absolute 
1041     if (pkgname == "*") 
1042       {
1043         int nbBssFiles;
1044         
1045         std::stringstream* stream = new std::stringstream;
1046         //if (upath.size()!=0) // avoid troubles for "*"
1047         
1048         // ==== no path provided : look in root bbs path
1049         if (upath.size()==0)
1050           {
1051             //      bbtkMessage("Interpreter",1,
1052             script_paths.push_back(  ConfigurationFile::GetInstance().Get_root_bbs_path() );
1053           }
1054         // ==== absolute path provided 
1055         else if (upath[0]=='/' || upath[1] == ':' ) 
1056           {
1057             if ( Utilities::IsDirectory( upath ) )
1058               {
1059                 script_paths.push_back(upath);
1060               }
1061             else 
1062               {
1063                 bbtkError("'"<<upath<<"' : directory does not exist"); 
1064               }
1065           }
1066         // ==== relative path provided : search all bbs path appended with 
1067         // the relative path provided
1068         else
1069           {    
1070              std::vector<std::string>::const_iterator i;
1071              for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1072                   i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1073                   i++)
1074                {
1075                  std::string full_path(*i);
1076                  // we *really* want '.' to be the current working directory
1077                  if (full_path == ".") {
1078                    char buf[2048]; // for getcwd
1079                    char * currentDir = getcwd(buf, 2048);
1080                    std::string cwd(currentDir);
1081                    full_path = currentDir;
1082                  } // if full_path
1083             
1084                  full_path += ConfigurationFile::GetInstance().Get_file_separator();
1085                  full_path += upath;
1086
1087                  if ( Utilities::IsDirectory( full_path ) )
1088                    {
1089                      script_paths.push_back(full_path);
1090                    }
1091                } 
1092              if (script_paths.empty())
1093                {
1094                  bbtkError("no '"<<upath<<"' subdir found in search paths" 
1095                            << std::endl);
1096                }
1097
1098           }
1099         // === search paths list complete : now explore it
1100
1101
1102         std::vector<std::string>::iterator i;
1103         for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1104           {
1105             bbtkMessage("Interpreter",1,
1106                         "--> Looking in '" << *i << "'" << std::endl);
1107          
1108             
1109             Filenames.clear();
1110             int nbFiles = Utilities::Explore(*i, false, Filenames);
1111             
1112             nbBssFiles = 0;
1113             for (std::vector<std::string>::iterator j = Filenames.begin(); 
1114                  j!= Filenames.end(); ++j)
1115               {
1116                 int lgr = (*j).size();
1117                 if (lgr < 5)
1118                   continue;  // ignore non .bbs file
1119                 if ((*j).substr(lgr-4, 4) != ".bbs")
1120                   continue;
1121                 
1122                 (*stream) << "include \"" << *j << "\"\n";
1123                 bbtkMessage("Interpreter",2,
1124                             "  --> Found '" << *j << "'" << std::endl);
1125                 
1126                 nbBssFiles++;
1127               } // for vector
1128             
1129             if (nbBssFiles==0)
1130               {
1131                 bbtkMessage("Interpreter",1,
1132                             "  --> No .bbs found"<< std::endl);
1133               } 
1134             else 
1135               {
1136                 bbtkMessage("Interpreter",1,
1137                             "  --> "<<nbBssFiles<<" .bbs found"<< std::endl);
1138                 SwitchToStream(stream);
1139               }
1140             
1141             //break; // a directory was found; we stop iterating
1142             // LG : No! We want all files included !
1143           } // for vector
1144         return;
1145       }  
1146     //=============== end pkgname=="*" ===========
1147
1148
1149     // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1150     // (not only a plain script name)
1151     // we trust him, and try to expland the directory name
1152     // WARNING : starting from current local directory :  ./whatYouWant  (./ mandatory!)
1153
1154     if (name[0]=='/' || name[1] == ':' || name[0]=='.')  // absolute path (linux/windows) or relative path
1155     { 
1156
1157       // ===========================================================check user supplied location
1158       fullnameGiven = true;
1159
1160       fullPathScriptName =  Utilities::ExpandLibName(name, false);
1161
1162       // allow user to always forget ".bbs"
1163       int l = fullPathScriptName.size();
1164
1165       if (l!=0) {
1166
1167       if (l>4)
1168       {
1169          if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1170          {
1171             fullPathScriptName = fullPathScriptName + ".bbs";
1172          }
1173       }
1174       else
1175       {
1176          fullPathScriptName = fullPathScriptName + ".bbs";   
1177       }
1178
1179       if ( Utilities::FileExists(fullPathScriptName))
1180       {
1181         foundFile = true;
1182       }
1183     } // endif l != 0
1184   }
1185   else
1186     // =============================== iterate on the paths
1187     {
1188       script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1189       std::string path;
1190       std::vector<std::string>::iterator i;
1191       for (i=script_paths.begin();i!=script_paths.end();++i)
1192         {
1193           path = *i;
1194           // we *really* want '.' to be the current working directory
1195           if (path == ".") {
1196             char buf[2048]; // for getcwd
1197             char * currentDir = getcwd(buf, 2048);
1198             std::string cwd(currentDir);
1199             path = currentDir;
1200           }
1201           
1202           fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1203           
1204           // Check if library exists
1205           if ( ! Utilities::FileExists(fullPathScriptName) )
1206             {
1207               // The following is *NOT* a debug time message :
1208               // It's a user intended message.
1209               // Please don't remove it.
1210               bbtkMessage("Interpreter",2,
1211                           "   [" <<fullPathScriptName <<"] : doesn't exist" 
1212                           <<std::endl);
1213               continue;  // try next path
1214             }
1215           bbtkMessage("Interpreter",2,
1216                       "   [" <<fullPathScriptName 
1217                       <<"] : found" <<std::endl);
1218           foundFile = true;
1219           break; // a script was found; we stop iterating
1220
1221         } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1222     }
1223     
1224     if (!foundFile)
1225       {
1226         if (fullnameGiven)
1227           if(fullPathScriptName == "")
1228             bbtkError("Path ["<<upath<<"] doesn't exist");
1229           else
1230             bbtkError("Script ["<<fullPathScriptName<<"] not found");
1231         else
1232           bbtkError("No ["<<pkgname<<".bbs] script found");
1233         return;
1234       }
1235     else
1236       LoadScript(fullPathScriptName,name);
1237     
1238     return;
1239   }
1240   //=======================================================================
1241
1242
1243   //=======================================================================
1244 void Interpreter::SwitchToStream( std::stringstream* stream )
1245 {
1246     mFile.push_back(stream);
1247     std::ostringstream buffer_name;
1248     bufferNb++;
1249     buffer_name << "buffer_" ;
1250
1251     if (mFileName.size()>0 )
1252     {
1253        buffer_name << mFileName.back() << "_" << mLine.back();
1254     }
1255     mFileName.push_back(buffer_name.str());
1256     mIncludeFileName.push_back(buffer_name.str());
1257     mLine.push_back(0);
1258 }
1259   //=======================================================================
1260
1261   //=======================================================================
1262
1263   void Interpreter::LoadScript( std::string fullPathScriptName,
1264                                 std::string includeScriptName)
1265   {
1266      Utilities::replace( fullPathScriptName , 
1267                          INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1268    
1269      if (find(mFileNameHistory.begin(),
1270               mFileNameHistory.end(),
1271               fullPathScriptName)!=mFileNameHistory.end())
1272      {
1273         return;
1274      }
1275
1276     std::ifstream* s;
1277     s = new std::ifstream;
1278     s->open(fullPathScriptName.c_str());
1279     if (!s->good())
1280     {
1281         bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1282         return;
1283     }
1284
1285     bbtkMessage("Interpreter",1,"   -->[" << fullPathScriptName 
1286                 << "] found" << std::endl);
1287
1288     mFile.push_back(s);
1289     mFileName.push_back(fullPathScriptName);
1290     mFileNameHistory.push_back(fullPathScriptName);
1291     mIncludeFileName.push_back(includeScriptName);
1292     mLine.push_back(0);
1293
1294     return;
1295   }
1296
1297   //=======================================================================
1298   /**
1299    *  
1300    */
1301   void Interpreter::CloseCurrentFile()
1302   {
1303     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1304                       <<std::endl);
1305
1306     if (mFile.size()==0)
1307     {
1308       bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1309       return;
1310     }
1311
1312     bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1313
1314     std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1315     if (file!=0) file->close();
1316
1317     delete mFile.back();
1318     mFile.pop_back();
1319     mFileName.pop_back();
1320     mIncludeFileName.pop_back();
1321     mLine.pop_back();
1322
1323     bbtkDebugMessage("Interpreter",9," Remains "
1324                      <<mFile.size()
1325                      <<" open"<<std::endl);
1326     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1327                      <<std::endl);
1328   }
1329   //=======================================================================
1330
1331  //=======================================================================
1332   /**
1333    *  
1334    */
1335   void Interpreter::CloseAllFiles()
1336   {
1337     bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1338                       <<std::endl);
1339
1340     while (mFile.size() != 0) 
1341     {
1342        CloseCurrentFile();
1343     }
1344     bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1345                       <<std::endl);
1346   }
1347   //=======================================================================
1348
1349
1350
1351   //=======================================================================
1352   /**
1353    *  
1354    */
1355   void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1356                                       CommandInfoType& info )
1357   {
1358     bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1359
1360     // searches the command keyword
1361     CommandDictType::iterator c;
1362     c = mCommandDict.find(words[0]);
1363     if ( c == mCommandDict.end() ) {
1364       bbtkError(words[0]<<" : unknown command");
1365     }
1366
1367     // tests the number of args 
1368     if ( ( words.size()-1 < c->second.argmin ) ||
1369          ( words.size()-1 > c->second.argmax ) )
1370     {
1371        HelpCommand(words[0]);
1372        bbtkError(words[0]<<" : wrong number of arguments");
1373     }
1374
1375     info = c->second;
1376     bbtkDecTab("Interpreter",9);
1377   }
1378   //=======================================================================
1379
1380
1381   //=======================================================================
1382   /// Displays help on all the commands
1383 void Interpreter::Help(const std::vector<std::string>& words)
1384 {
1385     unsigned int nbarg = words.size()-1;
1386
1387     if (nbarg==0) 
1388     {
1389        HelpCommands();
1390     }
1391     else if (nbarg==1) 
1392     {
1393       if (words[1]=="packages") 
1394       {
1395          GetExecuter()->GetFactory()->PrintPackages(true);
1396          return;
1397       }
1398       try 
1399       {
1400           HelpCommand(words[1]);
1401       }
1402       catch (bbtk::Exception e) 
1403       {
1404          try 
1405          {
1406             GetExecuter()->GetFactory()->HelpPackage(words[1]);
1407             if ( mUser != 0 )
1408               {
1409                 std::string url = 
1410                   ConfigurationFile::GetInstance().Get_doc_path();
1411                 url += "/bbdoc/" + words[1] + "/index.html";
1412                 if (Utilities::FileExists(url)) 
1413                   {
1414                     mUser->InterpreterUserViewHtmlPage(url);
1415                   }
1416               }
1417          }
1418          catch (bbtk::Exception f) 
1419          {
1420            try 
1421              {
1422                std::string package;
1423                GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1424                if ( mUser != 0 )
1425                  {
1426                    std::string url = 
1427                      ConfigurationFile::GetInstance().Get_doc_path();
1428                    url += "/bbdoc/" + package + "/index.html";
1429                    if (Utilities::FileExists(url)) 
1430                      {
1431                        url += "#" + words[1];
1432                        mUser->InterpreterUserViewHtmlPage(url);
1433                      }
1434                  }
1435              }
1436            catch (bbtk::Exception g) 
1437              {
1438                try
1439                  {
1440                    GetExecuter()->ShowRelations(words[1],"0","9999");
1441                  }
1442                catch (bbtk::Exception h){
1443                  bbtkError("\""<<words[1].c_str()
1444                            <<"\" is not a known command, package, black box type or black box name");
1445                }
1446              }
1447          }
1448       }
1449     }
1450     else if (nbarg==2) 
1451     {
1452       if (words[2]=="all")
1453       {
1454          if ( words[1]=="packages" )
1455          {
1456             GetExecuter()->GetFactory()->PrintPackages(true,true);
1457             return;
1458           }
1459          try 
1460          {
1461             GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1462          }
1463          catch (bbtk::Exception f) 
1464          {
1465          }
1466      }
1467      else 
1468      {
1469         HelpCommand(words[0]);
1470         bbtkError(words[0]<<" : syntax error");
1471      }
1472   }
1473   else 
1474   {
1475      bbtkError("Should not reach here !!!");
1476   }
1477 }
1478   //=======================================================================
1479
1480    //===================================================================    
1481   /// Displays the Configuration
1482   void Interpreter::Config() const
1483   {
1484     ConfigurationFile::GetInstance().GetHelp(1);
1485   }  
1486    //===================================================================    
1487
1488   //=======================================================================
1489   /// Displays help on all the commands
1490   void Interpreter::HelpCommands()
1491   {
1492     std::cout << "Available commands :" << std::endl;
1493     CommandDictType::iterator i;
1494     for ( i =  mCommandDict.begin();
1495           i != mCommandDict.end();
1496         ++i) {
1497               std::cout << " " << i->first << std::endl;
1498       //      std::cout << "   usage : " << i->second.syntax << std::endl;
1499       //     std::cout << "    " << i->second.help << std::endl;
1500
1501     }
1502   }
1503   //=======================================================================
1504
1505
1506   //=======================================================================
1507   /// Displays help on a particular commands
1508   void Interpreter::HelpCommand(const std::string& s)
1509   {
1510     CommandDictType::iterator c;
1511     c = mCommandDict.find(s);
1512     if ( c == mCommandDict.end() ) {
1513       bbtkError(s<<" : Unknown command");
1514     }
1515     //    std::cout << " " << s << " : "<<  std::endl;
1516     //    CommandParamDictType::iterator i;
1517     //    for ( i =  c->second.begin();
1518     //      i != c->second.end();
1519     //      ++i) {
1520     std::cout << " usage : " << c->second.syntax << std::endl;
1521     std::cout << "  " << c->second.help << std::endl;
1522
1523   }
1524   //=======================================================================
1525
1526
1527   //=======================================================================
1528   /// Fills the vector commands with the commands which 
1529   /// have the first n chars of buf for prefix
1530   /// TODO : skip initial spaces in buf and also return the position of first
1531   /// non blank char in buf
1532   void Interpreter::FindCommandsWithPrefix( char* buf,
1533                                             int n,
1534                                             std::vector<std::string>& commands )
1535   {
1536     CommandDictType::const_iterator i;
1537     for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1538     {
1539       if ((i->first).find(buf,0,n) == 0) 
1540         commands.push_back(i->first);
1541     }
1542   }
1543   //=======================================================================
1544
1545
1546
1547   //=======================================================================
1548 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1549   
1550   inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1551   inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1552   
1553   // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1554   // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1555   // E.G. STORE THIS IN bbtk_config.xml
1556 #define BBTK_UP_ARROW_KBCODE    0x00415B1B
1557 #define BBTK_DOWN_ARROW_KBCODE  0x00425B1B
1558 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1559 #define BBTK_LEFT_ARROW_KBCODE  0x00445B1B
1560 #define BBTK_BACKSPACE_KBCODE   0x00000008
1561 #define BBTK_DEL_KBCODE         0x0000007F
1562 #define BBTK_SPACE_KBCODE       0x00000020 
1563
1564   //=======================================================================
1565   void Interpreter::GetLineFromPrompt(std::string& s)
1566   {
1567     int c;
1568     int ind=0;
1569
1570     int MAX_LINE_SIZE = 160;
1571     int MAX_HISTORY_SIZE = 100;
1572
1573     char* newline = new char[MAX_LINE_SIZE];
1574     memset(newline,0,MAX_LINE_SIZE);
1575     char* histline = new char[MAX_LINE_SIZE];
1576     memset(histline,0,MAX_LINE_SIZE);
1577
1578     char* line = newline;
1579     int hist = mHistory.size();
1580
1581     write(1,"> ",2);
1582     while(1)
1583     {
1584        c=0;
1585        read ( STDIN_FILENO, &c, 4) ;
1586
1587        bbtkDebugMessage("debug",9,"[0x"<<std::hex<<c<<"]\n");
1588
1589        // Printable character
1590        if ( (ind<MAX_LINE_SIZE-1) &&
1591             ( c >= BBTK_SPACE_KBCODE ) && 
1592             ( c <  BBTK_DEL_KBCODE )) 
1593        {
1594           PrintChar(c);
1595           line[ind++]=c;
1596        }
1597       // CR
1598        else if (c=='\n')
1599        {
1600        // delete the unused line
1601           if (line==newline)
1602               delete histline;
1603           else
1604               delete newline;
1605    
1606     // empty lines are not stored in from history
1607           if (strlen(line)) 
1608           {
1609              // if history too long : delete oldest command
1610              if (mHistory.size()>MAX_HISTORY_SIZE) 
1611              {
1612                 delete mHistory.front();
1613                 mHistory.pop_front();
1614              }
1615              mHistory.push_back(line);
1616           }
1617           break;
1618         }
1619        // Backspace
1620         else if ( (ind>0) && 
1621                   ((c == BBTK_BACKSPACE_KBCODE) ||
1622                    (c == BBTK_DEL_KBCODE)) )
1623           {
1624             line[ind--]=' ';
1625             BackSpace();
1626           }
1627         // Tab 
1628         else if (c=='\t')
1629           {
1630             // TODO : Command completion  
1631             std::vector<std::string> commands;
1632             FindCommandsWithPrefix( line,ind,commands);
1633             if (commands.size()==1) 
1634               {
1635                 std::string com = *commands.begin();
1636                 for (; ind<com.size(); ++ind) 
1637                   {
1638                     PrintChar(com[ind]); 
1639                     line[ind]=com[ind];
1640                   }
1641                 PrintChar(' '); 
1642                 line[ind++]=' ';
1643               }
1644             else if (commands.size()>1) 
1645               {
1646                 std::vector<std::string>::iterator i;
1647                 write(1,"\n",1);
1648                 for (i=commands.begin();i!=commands.end();++i) 
1649                   {
1650                     write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1651                     PrintChar(' ');
1652                   }
1653                 write(STDOUT_FILENO,"\n> ",3);
1654                 //for (int j=0;j<ind;++j) 
1655                   //{
1656                     write(STDOUT_FILENO,line,ind); 
1657                     //  }
1658               }
1659           }
1660         // Arrow up : back in history
1661         else if (c==BBTK_UP_ARROW_KBCODE)
1662           {
1663             if (hist) 
1664               {
1665                 // erase current line
1666                 while (ind--) BackSpace();
1667                 // 
1668                 hist--;
1669                 // 
1670                 strcpy(histline,mHistory[hist]);
1671                 line = histline;
1672                 ind = strlen(line);
1673                 
1674                 write(STDOUT_FILENO,line,ind);
1675               }
1676           }
1677         // Arrow down : down in history
1678         else if (c==BBTK_DOWN_ARROW_KBCODE)
1679           {
1680             if (hist<mHistory.size()-1) 
1681               {
1682                 // erase current line
1683                 while (ind--) BackSpace();
1684                 // 
1685                 hist++;
1686                 // 
1687                 strcpy(histline,mHistory[hist]);
1688                 line = histline;
1689                 ind = strlen(line);
1690                 
1691                 write(STDOUT_FILENO,line,ind);
1692               }
1693             // end of history : switch back to newline
1694             else if (hist==mHistory.size()-1)
1695               {
1696                 // erase current line
1697                 while (ind--) BackSpace();
1698                 // 
1699                 hist++;
1700                 // 
1701                 line = newline;
1702                 ind = strlen(line);
1703                 
1704                 write(STDOUT_FILENO,line,ind);
1705               }
1706           }
1707         // Arrow right
1708         else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1709           {
1710             PrintChar(line[ind]);
1711             ind++;
1712           }
1713
1714         // Arrow left
1715         else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1716           {
1717             PrintChar('\b');
1718             ind--;
1719     
1720           }
1721
1722       }
1723     write(STDOUT_FILENO,"\n\r",2);
1724     
1725     
1726     s = line;
1727     
1728   }
1729 #else
1730
1731   //=======================================================================
1732   void Interpreter::GetLineFromPrompt(std::string& s)
1733   {  
1734     s.clear();
1735
1736     putchar('>');
1737     putchar(' ');
1738
1739     do 
1740     {
1741       char c = getchar();
1742       if (c=='\n') 
1743       {
1744         putchar('\n');
1745         break;
1746       }
1747       if (c=='\t') 
1748       {
1749         // putchar('T');
1750         continue;
1751       }
1752       // putchar(c);
1753       s += c;
1754     } 
1755     while (true);  
1756     
1757   }
1758   //=======================================================================  
1759
1760 #endif
1761
1762
1763
1764   //=======================================================================
1765   void Interpreter::CommandLineInterpreter()
1766   {
1767     bbtkDebugMessageInc("Interpreter",9,
1768                         "Interpreter::CommandLineInterpreter()"<<std::endl);
1769
1770 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT  
1771     // Initialise the tty in non canonical mode with no echo
1772     // oter remembers the previous settings to restore them after 
1773     struct termios ter,oter;
1774     tcgetattr(0,&ter);
1775     oter=ter;
1776     ter.c_lflag &= ~ECHO;
1777     ter.c_lflag &= ~ICANON;
1778     ter.c_cc[VMIN]=1;
1779     ter.c_cc[VTIME]=0;
1780     tcsetattr(0,TCSANOW,&ter);
1781 #endif
1782     
1783     mCommandLine = true;
1784     bool again = true;
1785     bool insideComment = false; // for multiline comment  
1786     do 
1787     {
1788       try
1789       {
1790         std::string line;
1791         GetLineFromPrompt(line);
1792         InterpretLine(line, insideComment);
1793       }
1794       catch (QuitException e)
1795       {
1796         bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1797         again = false;
1798       }
1799       catch (bbtk::Exception e) 
1800       {
1801         e.Print();
1802       }
1803         catch (std::exception& e) 
1804       {
1805         std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1806       }
1807       catch (...)
1808       {
1809         std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1810       }
1811     }
1812     while (again);
1813
1814 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1815     tcsetattr(0,TCSANOW,&oter);
1816 #endif
1817
1818     std::cout << "Good bye !" << std::endl;
1819
1820     bbtkDebugDecTab("Interpreter",9);
1821   }
1822
1823 //=======================================================================
1824 void Interpreter::Graph(const std::vector<std::string>& words)
1825 {
1826   std::string page;
1827     bool system_display = true;
1828
1829     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1830       system_display = false; 
1831  
1832     if (words.size()==1) 
1833     {
1834       page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1835     }
1836     else if (words.size()==2) 
1837     {
1838       page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1839     }
1840     else if (words.size()==3) 
1841     {
1842       page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1843     }
1844     else if (words.size()==4) 
1845     {
1846       page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1847     } 
1848     else if (words.size()==5) 
1849     {
1850       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1851     } 
1852     else if (words.size()==6) 
1853     {
1854       page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1855     } 
1856     else if (words.size()==7) 
1857       {
1858         page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1859       } 
1860     
1861     if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1862       mUser->InterpreterUserViewHtmlPage(page);
1863
1864   }
1865 //=======================================================================
1866
1867
1868 //=======================================================================
1869 void  Interpreter::Index(const std::string& filename, 
1870                          const std::string& type)
1871 {
1872   Factory::IndexEntryType t;
1873   if (type=="Initials") t = Factory::Initials;
1874   else if (type=="Categories") t = Factory::Categories;
1875   else if (type=="Packages") t = Factory::Packages;
1876   else if (type=="Adaptors") t = Factory::Adaptors;
1877   
1878   GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1879 }
1880 //=======================================================================
1881
1882
1883 //=======================================================================
1884 void  Interpreter::NewGUI(const std::string& boxname,
1885                              const std::string& instanceName)
1886 {
1887   std::string typeName = instanceName+"Type";
1888   std::stringstream* s = new std::stringstream;
1889   // create the complex box
1890   (*s) << "define "<<typeName<<std::endl;
1891   //  (*s) << "  description 'Automatically generated user interface for the box "
1892   //       << boxname << "'" <<std::endl;
1893   // create the Layout box
1894   (*s) << "  load wx"<<std::endl;
1895   (*s) << "  new LayoutLine layout"<<std::endl;
1896   // create the output 'Widget'
1897   (*s) << "  output Widget layout.Widget Widget"<<std::endl;
1898   // the box change output 
1899   (*s) << "  new MultipleInputs change"<<std::endl;
1900   (*s) << "  output BoxChange change.Out BoxChange"<<std::endl;
1901
1902   // Browse the inputs of the box in order to find which ones are not 
1903   // connected and can be adapted from a widget adaptor
1904   // vector which stores the list of inputs of the box which must be connected
1905   std::vector<std::string> in;
1906  
1907   Factory::Pointer F = mExecuter->GetFactory();
1908   /*
1909   Package::Pointer user = F->GetPackage("user");
1910   */
1911   ComplexBlackBoxDescriptor::Pointer workspace = mExecuter->GetWorkspace();
1912
1913   if (workspace==0)
1914     {
1915       delete s;
1916       bbtkError("Interpreter::CreateGUI : could not access the executer workspace");
1917     }
1918  
1919
1920   /*
1921     (ComplexBlackBoxDescriptor::Pointer)(user->GetBlackBoxMap().find("workspace")->second.get());
1922   */
1923
1924   BlackBox::Pointer box = workspace->GetPrototype()->bbGetBlackBox(boxname);
1925   //  BlackBox::InputConnectorMapType incm = box->bbGetInputConnectorMap();
1926   int nb = 0;
1927   BlackBox::InputConnectorMapType::iterator i;
1928   for (i=box->bbGetInputConnectorMap().begin();
1929        i!=box->bbGetInputConnectorMap().end();
1930        ++i)
1931     {
1932       // If the input is connected : continue
1933       if (i->second->IsConnected()) continue;
1934       // Get the input descriptor 
1935       const BlackBoxInputDescriptor* d = box->bbGetDescriptor()->GetInputDescriptor(i->first);
1936       // If it is a "system" input : skip it
1937       if ( ( d->GetCreatorTypeInfo() == typeid(AtomicBlackBoxDescriptor)) ||
1938            ( d->GetCreatorTypeInfo() == typeid(WxBlackBoxDescriptor)) )
1939         continue;
1940       bool widok = true;
1941       std::string widget,adaptor;
1942       // try to find a widget adaptor
1943       if (F->FindWidgetAdaptor(DataInfo(d->GetTypeInfo(),""),
1944                                d->GetDataInfo(),
1945                                adaptor))
1946         {
1947           // command to create the adaptor
1948           (*s) << "  new "<<adaptor<<" "<<i->first<<std::endl;
1949           // Sets the label of the widget adaptor to the name of the input
1950           (*s) << "  set "<<i->first<<".Label "<<i->first<<std::endl;
1951           // Sets the initial value of the widget to the value of the input
1952           (*s) << "  set "<<i->first<<".In \" "
1953                <<box->bbGetInputAsString(i->first)<<"\""
1954                << std::endl;
1955           // store the input name
1956           in.push_back(i->first);
1957           (*s) << "  connect "<<i->first<<".Widget layout.Widget"<<in.size()<<std::endl;
1958             //<i->first<<"'"<<std::endl;
1959           (*s) << "  connect "<<i->first<<".BoxChange change.In"<<in.size()<<std::endl;
1960         }
1961       // try to find a two pieces adaptor
1962       else if (F->FindWidgetAdaptor2(DataInfo(d->GetTypeInfo(),""),
1963                                      d->GetDataInfo(),
1964                                      widget,adaptor) )
1965         {
1966           // command to create the widget
1967           (*s) << "  new "<<widget<<" "<<i->first<<"Widget"<<std::endl;
1968           // command to create the adaptor
1969           (*s) << "  new "<<adaptor<<" "<<i->first<<std::endl;
1970           // connect the two
1971           (*s) << "  connect "<<i->first<<"Widget.Out "
1972                <<i->first<<".In"<<std::endl;
1973           // Sets the label of the widget adaptor to the name of the input
1974           (*s) << "  set "<<i->first<<"Widget.Label "<<i->first<<std::endl;
1975           // Sets the initial value of the widget to the value of the input
1976           (*s) << "  set "<<i->first<<"Widget.In \" "
1977                <<box->bbGetInputAsString(i->first)<<"\""<< std::endl;
1978           // store the input name
1979           in.push_back(i->first);
1980           (*s) << "  connect "<<i->first<<"Widget.Widget layout.Widget"<<in.size()<<std::endl;
1981             //<i->first<<"'"<<std::endl;
1982           (*s) << "  connect "<<i->first<<"Widget.BoxChange change.In"<<in.size()<<std::endl;
1983
1984         }
1985       // try to find an adaptor from string 
1986       // If found then can create a text input which 
1987       // will be automatically adapted 
1988       else if (F->FindAdaptor(DataInfo(typeid(std::string),""),
1989                                d->GetDataInfo(),
1990                                adaptor))
1991         {
1992           // command to create the adaptor
1993           (*s) << "  new InputText "<<i->first<<std::endl;
1994           // Sets the label of the widget adaptor to the name of the input
1995           (*s) << "  set "<<i->first<<".Title "<<i->first<<std::endl;
1996           // Sets the initial value of the widget to the value of the input
1997           (*s) << "  set "<<i->first<<".In \" "
1998                <<box->bbGetInputAsString(i->first)<<"\""<< std::endl;
1999           // store the input name
2000           in.push_back(i->first);
2001           (*s) << "  connect "<<i->first<<".Widget layout.Widget"<<in.size()<<std::endl;
2002             //<i->first<<"'"<<std::endl;
2003           (*s) << "  connect "<<i->first<<".BoxChange change.In"<<in.size()<<std::endl;
2004
2005         }
2006       else 
2007         {
2008           widok = false;
2009         }
2010       if (widok)
2011         {
2012           // command to create the output
2013           (*s) << "  output "<<i->first<<" "
2014                <<i->first<<".Out "<<i->first<<std::endl;
2015             //         <<" Output of the widget which allows to set "
2016           
2017         }
2018     }   
2019   // Inputs for window properties
2020   (*s) << "  input WinTitle layout.WinTitle Title"<<std::endl;
2021   (*s) << "  input WinWidth layout.WinWidth Width"<<std::endl;
2022   (*s) << "  input WinHeight layout.WinHeight Height"<<std::endl;
2023   (*s) << "  input WinDialog layout.WinDialog Dialog"<<std::endl;
2024   (*s) << "  input WinHide layout.WinHide Hide"<<std::endl;
2025
2026   
2027   
2028   // Execute the box executes the layout
2029   (*s) << "  exec layout" << std::endl;
2030   (*s) << "endefine" << std::endl;
2031   // (*s) << "help "<< typeName<< std::endl;
2032   // instanciate the box and connect it
2033   (*s) << "new "<<typeName<<" "<<instanceName<<std::endl;
2034   // connections
2035   std::vector<std::string>::iterator j;
2036   for (j=in.begin();j!=in.end();++j)
2037     {
2038       // connect
2039       (*s) << "connect "<<instanceName<<"."<<*j<<" "
2040            << boxname<<"."<<*j<<std::endl;
2041     }
2042   // That's all folks ! now execute the commands :
2043   SwitchToStream(s);
2044 }
2045 //=======================================================================
2046
2047
2048
2049  //==========================================================================
2050   void Interpreter::ObjectInfo(const std::string& name)
2051   {
2052     if ((name.length()==2)&&(name[0]=='-'))
2053       {
2054         if (name[1]=='S')
2055           {
2056             bbtk::StaticInitTime::PrintObjectListInfo = true;
2057           }
2058         if (name[1]=='C')
2059           {
2060             //      int o = MessageManager::GetMessageLevel("debug");
2061             //      if (o<2) MessageManager::SetMessageLevel("debug",2);
2062             mExecuter->GetFactory()->CheckPackages();
2063             //      MessageManager::SetMessageLevel("debug",o);
2064           }
2065       }
2066     else 
2067       {
2068         Object:: PrintObjectListInfo(name);
2069       }
2070   }
2071  //==========================================================================
2072  //==========================================================================
2073   std::string Interpreter::GetObjectName() const
2074   {
2075     return std::string("Interpreter");
2076   }
2077   //==========================================================================
2078   
2079   //==========================================================================
2080   std::string  Interpreter::GetObjectInfo() const 
2081   {
2082     std::stringstream i;
2083     return i.str();
2084   }
2085   //==========================================================================
2086
2087   //==========================================================================
2088 size_t  Interpreter::GetObjectSize() const 
2089 {
2090   size_t s = Superclass::GetObjectSize();
2091   s += Interpreter::GetObjectInternalSize();
2092   return s;
2093   }
2094   //==========================================================================
2095   //==========================================================================
2096 size_t  Interpreter::GetObjectInternalSize() const 
2097 {
2098   size_t s = sizeof(Interpreter);
2099   return s;
2100   }
2101   //==========================================================================
2102   //==========================================================================
2103   size_t  Interpreter::GetObjectRecursiveSize() const 
2104   {
2105     size_t s = Superclass::GetObjectRecursiveSize();
2106     s += Interpreter::GetObjectInternalSize();
2107     s += mExecuter->GetObjectRecursiveSize();
2108     return s;
2109   }
2110   //==========================================================================
2111 }//namespace
2112
2113