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