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