1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/01/22 15:02:00 $
7 Version: $Revision: 1.1 $
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.
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.
17 =========================================================================*/
20 * \brief class Interpreter :
23 #include "bbtkInterpreter.h"
24 #include "bbtkMessageManager.h"
25 #include "bbtkConfigurationFile.h"
26 #include "bbtkWxConsole.h"
27 #include "bbtkUtilities.h"
29 #ifdef CMAKE_HAVE_TERMIOS_H
31 #define BBTK_USE_TERMIOS_BASED_PROMPT
38 Interpreter* Interpreter::mGlobalInterpreter = NULL;
42 //=======================================================================
46 Interpreter::Interpreter()
48 mCommandLine(false), verbose(false)
50 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
51 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
52 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
55 mGlobalInterpreter = this;
57 // mFactory = new bbtk::Factory();
58 mExecuter = new bbtk::Executer();
59 //mExecuter->SetFactory(mFactory);
61 // Builds the commands dict
68 info.syntax = "new <type> <name>";
69 info.help = "Creates a new black box of type <type> with name <name>";
70 mCommandDict[info.keyword] = info;
72 info.keyword = "delete";
76 info.syntax = "delete <box>";
77 info.help = "Deletes the black box of name <box>";
78 mCommandDict[info.keyword] = info;
80 info.keyword = "connect";
84 info.syntax = "connect <box1.output> <box2.input>";
85 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
86 mCommandDict[info.keyword] = info;
88 info.keyword = "print";
92 info.syntax = "print <string>";
93 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').";
94 mCommandDict[info.keyword] = info;
96 info.keyword = "exec";
100 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
101 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.";
102 mCommandDict[info.keyword] = info;
104 info.keyword = "define";
108 info.syntax = "define <type> [<package>]";
109 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.";
110 mCommandDict[info.keyword] = info;
112 info.keyword = "endefine";
115 info.code = cEndDefine;
116 info.syntax = "endefine";
117 info.help = "Ends the definition of a new type of complex black box";
118 mCommandDict[info.keyword] = info;
120 info.keyword = "input";
124 info.syntax = "input <name> <box.input> <help>";
125 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";
126 mCommandDict[info.keyword] = info;
128 info.keyword = "output";
132 info.syntax = "output <name> <box.output> <help>";
133 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";
134 mCommandDict[info.keyword] = info;
136 info.keyword = "set";
140 info.syntax = "set <box.input> <value>";
141 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";
142 mCommandDict[info.keyword] = info;
144 info.keyword = "config"; // JPR
148 info.syntax = "config [<verbose>|<v>]";
149 info.help = "Prints the value of all configuration parameters";
150 mCommandDict[info.keyword] = info;
152 info.keyword = "reset"; //EED
156 info.syntax = "reset";
157 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
158 mCommandDict[info.keyword] = info;
160 info.keyword = "author";
164 info.syntax = "author <string>";
165 info.help = "Adds the string <string> to the author information of the black box being defined";
166 mCommandDict[info.keyword] = info;
168 info.keyword = "description";
171 info.code = cDescription;
172 info.syntax = "description <string>";
173 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
174 mCommandDict[info.keyword] = info;
176 info.keyword = "help";
180 info.syntax = "help";
181 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>";
182 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.";
183 mCommandDict[info.keyword] = info;
185 info.keyword = "message";
188 info.code = cMessage;
189 info.syntax = "message <category> <level>";
190 info.help = "Sets the level of the category of messages <category> to <level>.\n If category='All' then sets the level for all categories. If no category nor level is passed then prints info on available categories of messages and their current level.";
191 mCommandDict[info.keyword] = info;
193 info.keyword = "include";
196 info.code = cInclude;
197 info.syntax = "include <filename>";
198 info.help = "Includes the file <filename>";
199 mCommandDict[info.keyword] = info;
201 info.keyword = "quit";
205 info.syntax = "quit";
206 info.help = "Quits the program (during script execution it stops the complete execution)";
207 mCommandDict[info.keyword] = info;
209 info.keyword = "load";
213 info.syntax = "load <packagename>";
214 info.help = "Loads the black box package <packagename>";
215 mCommandDict[info.keyword] = info;
217 info.keyword = "unload";
221 info.syntax = "unload <packagename>";
222 info.help = "Unloads the black box package <packagename>";
223 mCommandDict[info.keyword] = info;
225 info.keyword = "graph";
229 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 ]]]]]]";
230 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')";
231 mCommandDict[info.keyword] = info;
234 info.keyword = "workspace";
237 info.code = cWorkspace;
238 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
239 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.";
240 mCommandDict[info.keyword] = info;
243 bbtkDebugDecTab("Interpreter",9);
246 //=======================================================================
250 //=======================================================================
254 Interpreter::~Interpreter()
256 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
260 // std::cout <<"EO Interpreter::~Interpreter()"<<std::endl;
261 bbtkDebugDecTab("Interpreter",9);
263 //=======================================================================
266 //=======================================================================
270 void Interpreter::InterpretFile( const std::string& filename, bool use_configuration_file, bool verbose)
272 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
274 bool exm = mCommandLine;
275 mCommandLine = false;
279 SwitchToFile(filename, use_configuration_file, verbose);
280 bool insideComment = false; // for multiline comment
281 while (mFile.size()>0)
283 while ((mFile.size()>0) &&
284 (!mFile.back()->eof()))
288 mFile.back()->getline(buf,500);
290 std::string str(buf);
291 int size=str.length();
292 if ( str[ size-1 ]==13 )
297 InterpretLine(str, insideComment);
299 //if (mFile.size()>0)
303 catch (QuitException e)
306 catch (bbtk::Exception e)
308 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
309 if (mFileName.size()) {
310 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
311 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
314 catch (std::exception& e)
316 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
317 if (mFileName.size()) {
318 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
319 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
324 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
325 if (mFileName.size()) {
326 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
327 std::cout << "* LINE : "<<mLine.back()<<std::endl;
332 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
333 bbtkDecTab("Interpreter",9);
337 //=======================================================================
341 //=======================================================================
345 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
348 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
349 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
351 std::vector<std::string> words;
352 SplitLine(line,words);
357 bbtkDebugDecTab("Interpreter",9);
361 // Single line comment : # or //
362 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
364 bbtkDebugDecTab("Interpreter",9);
365 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
369 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
371 if (words[0][0]=='/' && words[0][1]=='*')
373 bbtkDebugDecTab("Interpreter",9);
374 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
375 insideComment = true;
379 if (words[0][0]=='*' && words[0][1]=='/')
381 bbtkDebugDecTab("Interpreter",9);
382 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
383 if ( !insideComment ) {
384 bbtkDebugDecTab("Interpreter",9);
385 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
387 insideComment = false;
393 bbtkDebugDecTab("Interpreter",9);
394 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
399 CommandInfoType command;
400 InterpretCommand(words,command);
402 bbtkDebugMessage("Interpreter",9,
403 "Command '"<<command.keyword
404 <<" code="<<command.code<<std::endl);
406 std::string left,right,left2,right2;
407 std::string filename;
408 switch (command.code)
411 mExecuter->Create(words[1],words[2]);
416 // mExecuter->Remove(words[1]);
420 SplitAroundFirstDot(words[1],left,right);
421 SplitAroundFirstDot(words[2],left2,right2);
422 mExecuter->Connect(left,right,left2,right2);
426 if (mFileName.size()>0)
428 filename = Utilities::get_file_name(mFileName.back());
432 mExecuter->Define(words[1],"user",filename);
436 mExecuter->Define(words[1],words[2],filename);
441 mExecuter->EndDefine();
449 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
450 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
451 else mExecuter->Update(words[1]);
455 SplitAroundFirstDot(words[2],left,right);
456 mExecuter->DefineInput(words[1],left,right,words[3]);
460 SplitAroundFirstDot(words[2],left,right);
461 mExecuter->DefineOutput(words[1],left,right,words[3]);
465 SplitAroundFirstDot(words[1],left,right);
466 mExecuter->Set(left,right,words[2]);
470 mExecuter->Author(words[1]);
474 mExecuter->Description(words[1]);
484 bbtk::MessageManager::PrintInfo();
488 sscanf(words[2].c_str(),"%d",&level);
489 bbtk::MessageManager::SetMessageLevel(words[1],level);
498 if (words.size()>1) // any param for config means verbose = true
506 this->mExecuter->Reset();
512 InterpretFile(words[1], true, verbose); // true : better pass use_config_file
516 SwitchToFile(words[1], true, verbose); // true : better pass use_config_file
521 LoadPackage(words[1], true, verbose); // true : better pass use_config_file
525 UnLoadPackage(words[1]);
529 throw QuitException();
533 if (words.size() == 2)
535 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
536 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
540 mExecuter->SetWorkspaceName(words[2]);
545 bbtkInternalError("should not reach here !!!");
548 bbtkDecTab("Interpreter",9);
550 //=======================================================================
554 //=======================================================================
555 void SplitString ( const std::string& str, const std::string& delimiters,
556 std::vector<std::string>& tokens)
558 // Skip delimiters at beginning.
559 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
560 // Find first delimiter.
561 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
563 while (std::string::npos != pos || std::string::npos != lastPos)
565 // Found a token, add it to the vector.
566 tokens.push_back(str.substr(lastPos, pos - lastPos));
567 // Skip delimiters. Note the "not_of"
568 lastPos = str.find_first_not_of(delimiters, pos);
569 // Find next delimiter
570 pos = str.find_first_of(delimiters, lastPos);
574 //=======================================================================
578 //=======================================================================
582 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
584 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
586 std::string delimiters = "\"";
587 std::vector<std::string> quote;
588 SplitString(str,delimiters,quote);
591 std::vector<std::string>::iterator i;
592 for (i=quote.begin(); i!=quote.end(); )
594 SplitString(*i,delimiters,tokens);
598 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
599 tokens.push_back(*i);
604 for (i=tokens.begin(); i!=tokens.end(); ++i)
606 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
608 bbtkDebugMessageCont("Interpreter",9,std::endl);
610 bbtkDebugDecTab("Interpreter",9);
612 //=======================================================================
615 //=======================================================================
616 // Replaces substrings "\\n" by a real carriage return "\n"
617 void SubsBackslashN ( std::string& s )
619 // std::cout << "BEFORE=["<<s<<"]"<<std::endl;
620 std::string ss("\\n");
621 std::string::size_type pos = 0;
624 while ( pos != std::string::npos )
626 // std::cout << "*** find one "<<std::endl;
627 s.replace(pos,2,cr,1);
628 pos = s.find(ss, pos-1);
630 // std::cout << "AFTER=["<<s<<"]"<<std::endl;
632 //=======================================================================
635 //=======================================================================
639 void Interpreter::Print( const std::string& str)
641 if (mExecuter->GetNoExecMode()) return;
643 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
646 std::vector<std::string> chains;
647 std::string delimiters("$");
649 // Skip delimiters at beginning.
650 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
652 if (lastPos>0) is_text = false;
654 // Find first delimiter.
655 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
657 while (std::string::npos != pos || std::string::npos != lastPos)
661 // Found a text token, add it to the vector.
662 chains.push_back(str.substr(lastPos, pos - lastPos));
663 // std::cout << "text='"<<chains.back()<<"'"<<std::endl;
667 // is an output (between $$) : decode
668 std::string tok,box,output;
669 tok = str.substr(lastPos, pos - lastPos);
670 SplitAroundFirstDot(tok,box,output);
671 chains.push_back( mExecuter->Get(box,output) );
672 // std::cout << "outp='"<<chains.back()<<"'"<<std::endl;
674 // Skip delimiters. Note the "not_of"
675 lastPos = str.find_first_not_of(delimiters, pos);
676 // Find next delimiter
677 pos = str.find_first_of(delimiters, lastPos);
681 // std::cout << "nb="<<chains.size()<<std::endl;
682 std::vector<std::string>::iterator i;
683 for (i= chains.begin(); i!=chains.end(); ++i)
685 // bbtkMessage("Echo",1,*i);
689 std::cout << std::endl;
690 bbtkDebugDecTab("Interpreter",9);
693 //=======================================================================
699 // --> usefull in many places (at least : ConfigurationFile, Factory, Interpreter)
700 // should be factorized ( "bbtk::Util class ?)
702 bool Interpreter::FileExists(std::string strFilename)
703 bool Interpreter::IsAtRoot(std::string cwd)
704 std::string Interpreter::ExtractPackageName(const std::string &name)
705 std::string Interpreter::ExpandLibName(const std::string &name, bool verbose)
706 std::string Interpreter::MakeLibnameFromPath(std::string path, std::string pkgname)
708 // ===================================================================================
710 // See : http://www.techbytes.ca/techbyte103.html for more O.S.
711 bool Interpreter::FileExists(std::string strFilename) {
712 struct stat stFileInfo;
716 // Attempt to get the file attributes
717 intStat = stat(strFilename.c_str(),&stFileInfo);
719 // We were able to get the file attributes
720 // so the file obviously exists.
723 // We were not able to get the file attributes.
724 // This may mean that we don't have permission to
725 // access the folder which contains this file. If you
726 // need to do that level of checking, lookup the
727 // return values of stat which will give you
728 // more details on why stat failed.
735 // ===================================================================================
737 std::string Interpreter::ExtractScriptName(const std::string &name)
741 std::string::size_type slash_position = name.find_last_of("/\\");
742 if (slash_position != std::string::npos) {
743 pkgname =name.substr(slash_position+1,std::string::npos);
748 // remove {.bbs } if any
749 std::string::size_type dot_position = pkgname.find_last_of('.');
750 if (dot_position != std::string::npos){
751 pkgname = pkgname.substr(0,dot_position);
756 // ===================================================================================
758 std::string Interpreter::ExpandLibName(const std::string &name, bool verbose)
760 // ----- Think of expanding path name ( ./ ../ ../../ )
762 char buf[2048]; // for getcwd
763 char * currentDir = getcwd(buf, 2048);
764 std::string cwd(currentDir);
765 std::string libname(name);
767 // tooHigh : true is user supplies a library pathname with too many "../"
768 bool tooHigh = false;
770 if ( name[0] == '/' || name[0] == '\\' )
774 else if (name[0] == '.' && (name[1] == '/' || name[1] == '\\') )
776 libname = cwd + ConfigurationFile::GetInstance().Get_file_separator () + name.substr(2, name.length());
779 else if ( name[0] == '.' && name[1] == '.' && (name[2] == '/' || name[2] == '\\') )
781 if ( IsAtRoot(cwd) ) // hope it gets / (for Linux), C: D: (for Windows)
783 // if we are already at / or c: --> hopeless
785 std::cout << " File path [" << name << "] doesn't exist" << std::endl;
790 // iterate on ../ and go up from the current working dir!
792 bool alreadyProcessRoot = false;
795 std::string::size_type slash_position = cwd.find_last_of(ConfigurationFile::GetInstance().Get_file_separator ());
796 if (slash_position != std::string::npos) {
797 if (slash_position == 0)
799 cwd = cwd.substr(0,slash_position/*+1*/);
800 a = a.substr(3, name.length()); // remove ../
801 if (a == "" || alreadyProcessRoot)
804 std::cout << " File path [" << name << "] doesn't exist" << std::endl;
808 // std::string b = cwd + a;
810 char c = cwd[cwd.size()-1];
811 if (c != '/' && c != '\\' )
812 libname += ConfigurationFile::GetInstance().Get_file_separator ();
815 if ( a[0] != '.' ) // if . (probabely ../), loop again
819 alreadyProcessRoot = true;
821 } // end iterating on ../
827 } // ----- End of expanding path name ( ./ ../ ../../ )
830 return(""); // Will never get here!
834 // ===================================================================================
836 std::string Interpreter::MakeLibnameFromPath(std::string path, std::string pkgname)
838 std::string libname = path;
839 char c = path[path.size()-1];
840 if (c != '/' && c != '\\')
841 libname += ConfigurationFile::GetInstance().Get_file_separator ();
847 // ===================================================================================
849 bool Interpreter::IsAtRoot(std::string cwd)
851 if ( cwd == "/" // hope it gets / (for Linux)
852 || (cwd.size() <= 3 && cwd[1] == ':') ) // hope it gets C: D: (for Windows)
859 // ===================================================================================
862 void Interpreter::SwitchToFile( const std::string& name,
863 bool use_configuration_file, bool verbose)
865 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
866 <<name<<"\")"<<std::endl);
868 std::vector<std::string> script_paths;
869 std::string libname; // full path library name
870 std::string pkgname; // e.g. <scriptname>.bbs
872 pkgname = ExtractScriptName(name);
874 if (use_configuration_file)
877 std::cout << "look for : [" << name << "] (use_configuration_file == TRUE)" << std::endl;
878 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
881 bool fullnameGiven = false;
882 bool foundFile = false;
883 std::string::size_type slash_position = name.find_last_of("/\\");
885 if (slash_position != std::string::npos)
887 fullnameGiven = true;
888 libname = ExpandLibName(name, verbose);
890 if (FileExists(libname))
896 else // ----------------------- iterate on the paths
899 std::vector<std::string>::iterator i;
900 for (i=script_paths.begin();i!=script_paths.end();++i)
904 // we *really* want '.' to be the current working directory
906 char buf[2048]; // for getcwd
907 char * currentDir = getcwd(buf, 2048);
908 std::string cwd(currentDir);
912 libname = MakeLibnameFromPath(path, pkgname);
914 // Check if library exists
915 if ( !FileExists(libname) )
918 std::cout <<" [" <<libname <<"] : doesn't exist" <<std::endl;
919 continue; // try next path
922 break; // a script was found; we stop iterating
924 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
933 bbtkError("Path \""<<name<<"\" doesn't exist");
935 bbtkError("Script \""<<libname<<"\" not found");
937 bbtkError("No \""<<pkgname<<".bbs\" script found");
941 bbtkMessage("Interpreter",1,pkgname<<" loaded"<<std::endl);
943 s = new std::ifstream;
944 s->open(libname.c_str());
947 bbtkError("Could not open file \""<<libname<<"\"");
952 std::cout << " -->[" << libname << "] found" << std::endl;
955 mFileName.push_back(libname);
960 //=======================================================================
963 //=======================================================================
967 void Interpreter::CloseCurrentFile()
969 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
974 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
978 mFile.back()->close();
981 bbtkDebugMessage("Interpreter",9,
982 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
984 mFileName.pop_back();
986 bbtkDebugMessage("Interpreter",9," Remains "
988 <<" open"<<std::endl);
989 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
992 //=======================================================================
994 //=======================================================================
998 void Interpreter::CloseAllFiles()
1000 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1003 while (mFile.size() != 0)
1005 mFile.back()->close();
1006 delete mFile.back();
1008 bbtkDebugMessage("Interpreter",9,
1009 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1010 mFileName.pop_back();
1013 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1016 //=======================================================================
1020 //=======================================================================
1024 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1025 CommandInfoType& info )
1027 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1029 // searches the command keyword
1030 CommandDictType::iterator c;
1031 c = mCommandDict.find(words[0]);
1032 if ( c == mCommandDict.end() ) {
1033 bbtkError(words[0]<<" : unknown command");
1036 // tests the number of args
1037 if ( ( words.size()-1 < c->second.argmin ) ||
1038 ( words.size()-1 > c->second.argmax ) )
1040 HelpCommand(words[0]);
1041 bbtkError(words[0]<<" : wrong number of arguments");
1045 bbtkDecTab("Interpreter",9);
1047 //=======================================================================
1050 //=======================================================================
1051 /// Displays help on all the commands
1052 void Interpreter::Help(const std::vector<std::string>& words)
1054 unsigned int nbarg = words.size()-1;
1062 if (words[1]=="packages")
1064 PrintPackages(true);
1069 HelpCommand(words[1]);
1071 catch (bbtk::Exception e)
1075 HelpPackage(words[1]);
1077 catch (bbtk::Exception f)
1081 HelpBlackBox(words[1]);
1083 catch (bbtk::Exception g)
1087 this->mExecuter->ShowRelations(words[1],"0","9999");
1089 catch (bbtk::Exception h){
1090 bbtkError("\""<<words[1].c_str()
1091 <<"\" is not a known command, package, black box type or black box name");
1099 if (words[2]=="all")
1101 if ( words[1]=="packages" )
1103 PrintPackages(true,true);
1108 HelpPackage(words[1],true);
1110 catch (bbtk::Exception f)
1116 HelpCommand(words[0]);
1117 bbtkError(words[0]<<" : syntax error");
1122 bbtkError("Should not reach here !!!");
1125 //=======================================================================
1127 //===================================================================
1128 /// Displays the Configuration
1129 void Interpreter::Config( bool verbose ) const
1131 bbtkDebugMessageInc("Core",9,"Factory::Config"<<std::endl);
1133 ConfigurationFile cf = ConfigurationFile::GetInstance();
1135 const std::string config_xml_full_path = cf.Get_config_xml_full_path();
1136 const std::string description = cf.Get_description();
1137 const std::string url = cf.Get_url();
1138 const std::string data_path = cf.Get_data_path();
1139 const std::string default_doc_tmp = cf.Get_default_doc_tmp();
1140 const std::string file_separator = cf.Get_file_separator();
1141 const std::vector<std::string>bbs_paths = cf.Get_bbs_paths();
1142 const std::vector<std::string>package_paths = cf.Get_package_paths();
1144 bbtkMessage("Help",1, "=============" << std::endl);
1145 bbtkMessage("Help",1, "Configuration" << std::endl);
1146 bbtkMessage("Help",1, "=============" << std::endl);
1147 bbtkMessage("Help",1, "bbtk_config.xml : [" << config_xml_full_path << "]" << std::endl);
1148 bbtkMessage("Help",1, "Documentation Url : [" << url << "]" << std::endl);
1149 bbtkMessage("Help",1, "Data Path : [" << data_path << "]" << std::endl);
1150 bbtkMessage("Help",1, "Default Doc_tmp : [" << default_doc_tmp << "]" << std::endl);
1151 bbtkMessage("Help",1, "File Separator : [" << file_separator << "]" << std::endl);
1153 std::vector<std::string>::const_iterator i;
1155 bbtkMessage("Help",1, "BBS Paths " << std::endl);
1156 for (i = bbs_paths.begin(); i!=bbs_paths.end(); ++i )
1158 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1161 bbtkMessage("Help",1, "PACKAGE Paths : " << std::endl);
1162 for (i = package_paths.begin(); i!=package_paths.end(); ++i )
1164 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1167 bbtkDebugDecTab("Core",9);
1170 //=======================================================================
1171 /// Displays help on all the commands
1172 void Interpreter::HelpCommands()
1174 std::cout << "Available commands :" << std::endl;
1175 CommandDictType::iterator i;
1176 for ( i = mCommandDict.begin();
1177 i != mCommandDict.end();
1179 std::cout << " " << i->first << std::endl;
1180 // std::cout << " usage : " << i->second.syntax << std::endl;
1181 // std::cout << " " << i->second.help << std::endl;
1185 //=======================================================================
1188 //=======================================================================
1189 /// Displays help on a particular commands
1190 void Interpreter::HelpCommand(const std::string& s)
1192 CommandDictType::iterator c;
1193 c = mCommandDict.find(s);
1194 if ( c == mCommandDict.end() ) {
1195 bbtkError(s<<" : Unknown command");
1197 // std::cout << " " << s << " : "<< std::endl;
1198 // CommandParamDictType::iterator i;
1199 // for ( i = c->second.begin();
1200 // i != c->second.end();
1202 std::cout << " usage : " << c->second.syntax << std::endl;
1203 std::cout << " " << c->second.help << std::endl;
1206 //=======================================================================
1209 //=======================================================================
1210 /// Fills the vector commands with the commands which
1211 /// have the first n chars of buf for prefix
1212 /// TODO : skip initial spaces in buf and also return the position of first
1213 /// non blank char in buf
1214 void Interpreter::FindCommandsWithPrefix( char* buf,
1216 std::vector<std::string>& commands )
1218 CommandDictType::const_iterator i;
1219 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1221 if ((i->first).find(buf,0,n) == 0)
1222 commands.push_back(i->first);
1225 //=======================================================================
1229 //=======================================================================
1230 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1232 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1233 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1235 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1236 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1237 // E.G. STORE THIS IN bbtk_config.xml
1238 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1239 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1240 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1241 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1242 #define BBTK_BACKSPACE_KBCODE 0x00000008
1243 #define BBTK_DEL_KBCODE 0x0000007F
1244 #define BBTK_SPACE_KBCODE 0x00000020
1246 //=======================================================================
1247 void Interpreter::GetLineFromPrompt(std::string& s)
1252 int MAX_LINE_SIZE = 160;
1253 int MAX_HISTORY_SIZE = 100;
1255 char* newline = new char[MAX_LINE_SIZE];
1256 memset(newline,0,MAX_LINE_SIZE);
1257 char* histline = new char[MAX_LINE_SIZE];
1258 memset(histline,0,MAX_LINE_SIZE);
1260 char* line = newline;
1261 int hist = mHistory.size();
1268 read ( STDIN_FILENO, &c, 4) ;
1270 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1272 // Printable character
1273 if ( (ind<MAX_LINE_SIZE-1) &&
1274 ( c >= BBTK_SPACE_KBCODE ) &&
1275 ( c < BBTK_DEL_KBCODE ))
1283 // delete the unused line
1289 // empty lines are not stored in from history
1292 // if history too long : delete oldest command
1293 if (mHistory.size()>MAX_HISTORY_SIZE)
1295 delete mHistory.front();
1296 mHistory.pop_front();
1298 mHistory.push_back(line);
1304 else if ( (ind>0) &&
1305 ((c == BBTK_BACKSPACE_KBCODE) ||
1306 (c == BBTK_DEL_KBCODE)) )
1314 // TODO : Command completion
1315 std::vector<std::string> commands;
1316 FindCommandsWithPrefix( line,ind,commands);
1317 if (commands.size()==1)
1319 std::string com = *commands.begin();
1320 for (; ind<com.size(); ++ind)
1322 PrintChar(com[ind]);
1328 else if (commands.size()>1)
1330 std::vector<std::string>::iterator i;
1332 for (i=commands.begin();i!=commands.end();++i)
1334 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1337 write(STDOUT_FILENO,"\n> ",3);
1338 //for (int j=0;j<ind;++j)
1340 write(STDOUT_FILENO,line,ind);
1344 // Arrow up : back in history
1345 else if (c==BBTK_UP_ARROW_KBCODE)
1349 // erase current line
1350 while (ind--) BackSpace();
1354 strcpy(histline,mHistory[hist]);
1358 write(STDOUT_FILENO,line,ind);
1361 // Arrow down : down in history
1362 else if (c==BBTK_DOWN_ARROW_KBCODE)
1364 if (hist<mHistory.size()-1)
1366 // erase current line
1367 while (ind--) BackSpace();
1371 strcpy(histline,mHistory[hist]);
1375 write(STDOUT_FILENO,line,ind);
1377 // end of history : switch back to newline
1378 else if (hist==mHistory.size()-1)
1380 // erase current line
1381 while (ind--) BackSpace();
1388 write(STDOUT_FILENO,line,ind);
1392 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1394 PrintChar(line[ind]);
1399 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1407 write(STDOUT_FILENO,"\n\r",2);
1415 //=======================================================================
1416 void Interpreter::GetLineFromPrompt(std::string& s)
1442 //=======================================================================
1448 //=======================================================================
1449 void Interpreter::CommandLineInterpreter()
1451 bbtkDebugMessageInc("Interpreter",9,
1452 "Interpreter::CommandLineInterpreter()"<<std::endl);
1454 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1455 // Initialise the tty in non canonical mode with no echo
1456 // oter remembers the previous settings to restore them after
1457 struct termios ter,oter;
1460 ter.c_lflag &= ~ECHO;
1461 ter.c_lflag &= ~ICANON;
1464 tcsetattr(0,TCSANOW,&ter);
1467 mCommandLine = true;
1469 bool insideComment = false; // for multiline comment
1475 GetLineFromPrompt(line);
1476 InterpretLine(line, insideComment);
1478 catch (QuitException e)
1482 catch (bbtk::Exception e)
1486 catch (std::exception& e)
1488 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
1492 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1497 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1498 tcsetattr(0,TCSANOW,&oter);
1501 std::cout << "Good bye !" << std::endl;
1503 bbtkDebugDecTab("Interpreter",9);
1505 //=======================================================================
1508 //=======================================================================
1509 void Interpreter::SplitAroundFirstDot( const std::string& in,
1513 bbtkDebugMessageInc("Interpreter",9,
1514 "Interpreter::SplitAroundFirstDot(\""
1515 <<in<<"\")"<<std::endl);
1517 std::string delimiter = ".";
1518 std::string::size_type pos = in.find_first_of(delimiter);
1519 if (std::string::npos != pos)
1521 left = in.substr(0,pos);
1522 right = in.substr(pos+1,in.size());
1523 bbtkDebugMessage("Interpreter",9,
1524 "["<<left<<"] ["<<right<<"]"<<std::endl);
1528 bbtkError(in<<" : expected 'a.b' format but no dot found");
1531 bbtkDebugDecTab("Interpreter",9);
1533 //=======================================================================
1537 //=======================================================================
1538 void Interpreter::Graph(const std::vector<std::string>& words)
1541 bool system_display = true;
1543 #ifdef _USE_WXWIDGETS_
1544 if ( WxConsole::GetInstance() != 0 ) system_display = false;
1547 if (words.size()==1)
1549 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1551 else if (words.size()==2)
1553 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1555 else if (words.size()==3)
1557 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1559 else if (words.size()==4)
1561 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1563 else if (words.size()==5)
1565 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1567 else if (words.size()==6)
1569 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1571 else if (words.size()==7)
1573 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1576 #ifdef _USE_WXWIDGETS_
1577 if ( WxConsole::GetInstance() != 0 )
1578 WxConsole::GetInstance()->ShowHtmlPage(page);
1581 //=======================================================================