1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/07 08:40:14 $
7 Version: $Revision: 1.40 $
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"
30 #ifdef CMAKE_HAVE_TERMIOS_H
32 #define BBTK_USE_TERMIOS_BASED_PROMPT
40 //Interpreter* Interpreter::mGlobalInterpreter = NULL;
42 //=======================================================================
46 Interpreter::Interpreter()
48 #ifdef _USE_WXWIDGETS_
53 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
54 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
55 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
57 mExecuter = new bbtk::Executer();
58 mExecuter->SetInterpreter(this);
60 // For the time being, comment out previous line, and
61 // uncomment next line to check Transcriptor
63 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
65 // Builds the commands dict
68 info.category = "new";
72 info.syntax = "new <type> <name>";
73 info.help = "Creates a new black box of type <type> with name <name>";
74 mCommandDict[info.category] = info;
76 info.category = "delete";
80 info.syntax = "delete <box>";
81 info.help = "Deletes the black box of name <box>";
82 mCommandDict[info.category] = info;
84 info.category = "connect";
88 info.syntax = "connect <box1.output> <box2.input>";
89 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
90 mCommandDict[info.category] = info;
92 info.category = "print";
96 info.syntax = "print <string>";
97 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').";
98 mCommandDict[info.category] = info;
100 info.category = "exec";
104 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
105 info.help = "Executes the black box of name <box> (and connected boxes if needed). If the special category 'freeze' is given then freezes any further execution command. 'unfreeze' reverts to normal execution mode.";
106 mCommandDict[info.category] = info;
108 info.category = "package";
111 info.code = cPackage;
112 info.syntax = "package <name>";
113 info.help = "Begins the definition of a package.";
114 mCommandDict[info.category] = info;
116 info.category = "endpackage";
119 info.code = cEndPackage;
120 info.syntax = "endpackage";
121 info.help = "Ends the definition of a package.";
122 mCommandDict[info.category] = info;
124 info.category = "define";
128 info.syntax = "define <type> [<package>]";
129 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.";
130 mCommandDict[info.category] = info;
132 info.category = "endefine";
135 info.code = cEndDefine;
136 info.syntax = "endefine";
137 info.help = "Ends the definition of a new type of complex black box";
138 mCommandDict[info.category] = info;
140 info.category = "input";
144 info.syntax = "input <name> <box.input> <help>";
145 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";
146 mCommandDict[info.category] = info;
148 info.category = "output";
152 info.syntax = "output <name> <box.output> <help>";
153 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";
154 mCommandDict[info.category] = info;
156 info.category = "set";
160 info.syntax = "set <box.input> <value>";
161 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";
162 mCommandDict[info.category] = info;
164 info.category = "config"; // JPR
168 info.syntax = "config";
169 info.help = "Prints the value of all configuration parameters";
170 mCommandDict[info.category] = info;
172 info.category = "index"; // LG
177 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
178 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.";
179 mCommandDict[info.category] = info;
181 info.category = "reset"; //EED
185 info.syntax = "reset";
186 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
187 mCommandDict[info.category] = info;
189 info.category = "author";
193 info.syntax = "author <string>";
194 info.help = "Adds the string <string> to the author information of the black box being defined";
195 mCommandDict[info.category] = info;
197 info.category = "category"; //JP
200 info.code = cCategory;
201 info.syntax = "category <list of items, separated by ;>";
202 info.help = "Adds the string <string> to the category information of the black box being defined";
203 mCommandDict[info.category] = info;
205 info.category = "description";
208 info.code = cDescription;
209 info.syntax = "description <string>";
210 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
211 mCommandDict[info.category] = info;
213 info.category = "help";
217 info.syntax = "help";
218 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>";
219 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.";
220 mCommandDict[info.category] = info;
222 info.category = "message";
225 info.code = cMessage;
226 info.syntax = "message <kind> <level>";
227 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.category] = info;
229 info.category = "include";
232 info.code = cInclude;
233 info.syntax = "include <filename> [source]";
234 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).";
235 mCommandDict[info.category] = info;
237 info.category = "quit";
241 info.syntax = "quit";
242 info.help = "Quits the program (during script execution it stops the complete execution)";
243 mCommandDict[info.category] = info;
245 info.category = "load";
249 info.syntax = "load <packagename>";
250 info.help = "Loads the black box package <packagename>";
251 mCommandDict[info.category] = info;
253 info.category = "unload";
257 info.syntax = "unload <packagename>";
258 info.help = "Unloads the black box package <packagename>";
259 mCommandDict[info.category] = info;
261 info.category = "graph";
265 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 ]]]]]]";
266 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')";
267 mCommandDict[info.category] = info;
270 info.category = "workspace";
273 info.code = cWorkspace;
274 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
275 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.";
276 mCommandDict[info.category] = info;
279 bbtkDebugDecTab("Interpreter",9);
282 //=======================================================================
286 //=======================================================================
290 Interpreter::~Interpreter()
293 std::cout << "=========================================~Interpreter()" << std::endl;
294 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
297 bbtkDebugDecTab("Interpreter",9);
299 //=======================================================================
302 //=======================================================================
306 void Interpreter::InterpretFile( const std::string& filename )
308 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
310 bool exm = mCommandLine;
311 mCommandLine = false;
315 SwitchToFile(filename);
316 bool insideComment = false; // for multiline comment
317 while (mFile.size()>0)
319 while ((mFile.size()>0) &&
320 (!mFile.back()->eof()))
324 mFile.back()->getline(buf,500);
326 std::string str(buf);
327 int size=str.length();
328 if ( str[ size-1 ]==13 )
333 InterpretLine(str, insideComment);
335 //if (mFile.size()>0)
339 catch (QuitException e)
342 catch (bbtk::Exception e)
344 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
345 if (mFileName.size()) {
346 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
347 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
350 catch (std::exception& e)
352 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
353 if (mFileName.size()) {
354 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
355 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
360 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
361 if (mFileName.size()) {
362 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
363 std::cout << "* LINE : "<<mLine.back()<<std::endl;
368 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
369 bbtkDecTab("Interpreter",9);
373 //=======================================================================
377 //=======================================================================
381 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
384 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
385 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
387 std::vector<std::string> words;
388 SplitLine(line,words);
393 bbtkDebugDecTab("Interpreter",9);
397 // Single line comment : # or //
398 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
400 bbtkDebugDecTab("Interpreter",9);
401 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
405 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
407 if (words[0][0]=='/' && words[0][1]=='*')
409 bbtkDebugDecTab("Interpreter",9);
410 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
411 insideComment = true;
415 if (words[0][0]=='*' && words[0][1]=='/')
417 bbtkDebugDecTab("Interpreter",9);
418 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
419 if ( !insideComment ) {
420 bbtkDebugDecTab("Interpreter",9);
421 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
423 insideComment = false;
429 bbtkDebugDecTab("Interpreter",9);
430 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
435 CommandInfoType command;
436 InterpretCommand(words,command);
438 bbtkDebugMessage("Interpreter",9,
439 "Command='"<<command.category
440 <<"' code="<<command.code<<std::endl);
442 std::string left,right,left2,right2;
443 std::string filename;
444 switch (command.code)
447 mExecuter->Create(words[1],words[2]);
452 // mExecuter->Remove(words[1]);
456 Utilities::SplitAroundFirstDot(words[1],left,right);
457 Utilities::SplitAroundFirstDot(words[2],left2,right2);
458 mExecuter->Connect(left,right,left2,right2);
462 mExecuter->BeginPackage(words[1]);
466 mExecuter->EndPackage();
470 if (mFileName.size()>0)
472 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
476 mExecuter->Define(words[1],"",filename);
480 mExecuter->Define(words[1],words[2],filename);
485 mExecuter->EndDefine();
489 Print(words[1]); /// \todo use generate command
493 if (words[1]=="freeze")
494 mExecuter->SetNoExecMode(true);
495 else if (words[1]=="unfreeze")
496 mExecuter->SetNoExecMode(false);
498 mExecuter->Update(words[1]);
502 Utilities::SplitAroundFirstDot(words[2],left,right);
503 mExecuter->DefineInput(words[1],left,right,words[3]);
507 Utilities::SplitAroundFirstDot(words[2],left,right);
508 mExecuter->DefineOutput(words[1],left,right,words[3]);
512 Utilities::SplitAroundFirstDot(words[1],left,right);
513 mExecuter->Set(left,right,words[2]);
517 mExecuter->Author(words[1]);
521 mExecuter->Category(words[1]);
526 Index("tmp_index.html");
527 else if (words.size()==2)
529 else if (words.size()==3)
530 Index(words[1],words[2]);
534 mExecuter->Description(words[1]);
544 bbtk::MessageManager::PrintInfo();
548 sscanf(words[2].c_str(),"%d",&level);
549 bbtk::MessageManager::SetMessageLevel(words[1],level);
562 this->mExecuter->Reset();
568 InterpretFile(words[1]);
572 SwitchToFile(words[1]);
574 // if 'source' was given
577 GetExecuter()->SetCurrentFileName(words[1]);
582 GetExecuter()->GetFactory()->LoadPackage(words[1]);
586 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
591 throw QuitException();
595 if (words.size() == 2)
597 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
598 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
602 mExecuter->SetWorkspaceName(words[2]);
607 bbtkInternalError("should not reach here !!!");
610 bbtkDecTab("Interpreter",9);
612 //=======================================================================
618 //=======================================================================
622 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
624 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
626 std::string delimiters = "\"";
627 std::vector<std::string> quote;
628 Utilities::SplitString(str,delimiters,quote);
631 std::vector<std::string>::iterator i;
632 for (i=quote.begin(); i!=quote.end(); )
634 Utilities::SplitString(*i,delimiters,tokens);
638 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
639 tokens.push_back(*i);
644 for (i=tokens.begin(); i!=tokens.end(); ++i)
646 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
648 bbtkDebugMessageCont("Interpreter",9,std::endl);
650 bbtkDebugDecTab("Interpreter",9);
652 //=======================================================================
655 //=======================================================================
656 // Replaces substrings "\\n" by a real carriage return "\n"
657 void SubsBackslashN ( std::string& s )
659 std::string ss("\\n");
660 std::string::size_type pos = 0;
663 while ( pos != std::string::npos )
665 s.replace(pos,2,cr,1);
666 pos = s.find(ss, pos-1);
669 //=======================================================================
672 //=======================================================================
676 void Interpreter::Print( const std::string& str)
678 if (mExecuter->GetNoExecMode()) return;
680 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
683 // InterpretLine ("load std")
684 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
685 // InterpretLine("new Print _P_")
686 // InterpretLine("connect _C_.Out _P_.In")
690 std::vector<std::string> chains;
691 std::string delimiters("$");
693 // Skip delimiters at beginning.
694 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
696 if (lastPos>0) is_text = false;
698 // Find first delimiter.
699 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
701 while (std::string::npos != pos || std::string::npos != lastPos)
705 // Found a text token, add it to the vector.
706 chains.push_back(str.substr(lastPos, pos - lastPos));
707 // std::string token = str.substr(lastPos, pos - lastPos)
708 // InterpretLine("set _C_.In%num% %token%")
714 // is an output (between $$) : decode
715 std::string tok,box,output;
716 tok = str.substr(lastPos, pos - lastPos);
717 Utilities::SplitAroundFirstDot(tok,box,output);
718 chains.push_back( mExecuter->Get(box,output) );
720 // InterpretLine("connect %tok% _C_.In%num%")
723 // Skip delimiters. Note the "not_of"
724 lastPos = str.find_first_not_of(delimiters, pos);
725 // Find next delimiter
726 pos = str.find_first_of(delimiters, lastPos);
731 // InterpretLine("exec _P_")
732 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
734 std::vector<std::string>::iterator i;
735 for (i= chains.begin(); i!=chains.end(); ++i)
737 // bbtkMessage("Echo",1,*i);
741 std::cout << std::endl;
742 bbtkDebugDecTab("Interpreter",9);
745 //=======================================================================
750 // ===================================================================================
752 void Interpreter::SwitchToFile( const std::string& name )
754 // Note : in the following :
755 // name : the user supplied name
756 // - abreviated name e.g. scr scr.bbs
757 // - relative full name e.g. ./scr.bbs ../../scr.bbs
758 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
759 // same for Windows, with c:, d: ...
761 // use ./directory/subdir/scrname.bbs
764 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
765 <<name<<"\")"<<std::endl);
767 std::vector<std::string> script_paths;
768 std::string fullPathScriptName; // full path script name
769 std::string pkgname; // e.g. <scriptname>.bbs
770 std::vector<std::string> Filenames;
772 // The following is *NOT* a debug time message :
773 // It's a user intended message.
774 // Please don't remove it.
775 bbtkMessage("Interpreter",1,
776 "look for : [" << name
777 << "]" << std::endl);
778 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
781 pkgname = Utilities::ExtractScriptName(name,upath);
783 bool fullnameGiven = false;
784 bool foundFile = false;
786 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
790 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
792 int nbFiles = Utilities::Explore(upath, false, Filenames);
794 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
796 if ((*i).substr((*i).size()-4, 4) != ".bbs")
797 continue; // ignore non .bbs files
802 bbtkMessage("Interpreter",2,
803 "WARNING : No '.bbs' file found in ["
804 << upath << "]" << std::endl);
809 std::vector<std::string>::iterator i;
810 std::string fullDirectoryName;
811 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
815 // we *really* want '.' to be the current working directory
817 char buf[2048]; // for getcwd
818 char * currentDir = getcwd(buf, 2048);
819 std::string cwd(currentDir);
823 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
826 // without last slash "\"
827 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
829 // Check if library exists
830 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
832 // The following is *NOT* a debug time message :
833 // It's a user intended message.
834 // Please don't remove it.
835 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
836 <<"] : doesn't exist" <<std::endl);
837 continue; // try next path
842 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
845 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
847 if ((*i).substr((*i).size()-4, 4) != ".bbs")
848 continue; // ignore non .bbs files
853 bbtkMessage("Interpreter",1,
854 "WARNING : No '.bbs' file found in ["
855 << fullDirectoryName << "]" << std::endl);
857 //break; // a directory was found; we stop iterating
858 // LG : No! We want all files included !
863 //std::string::size_type slash_position = name.find_last_of("/\\");
865 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
866 // (not only a plain script name)
867 // we trust him, and try to expland the directory name
868 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
870 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
873 // ===========================================================check user supplied location
874 fullnameGiven = true;
876 fullPathScriptName = Utilities::ExpandLibName(name, false);
878 // allow user to always forget ".bbs"
879 int l = fullPathScriptName.size();
885 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
887 fullPathScriptName = fullPathScriptName + ".bbs";
892 fullPathScriptName = fullPathScriptName + ".bbs";
895 if ( Utilities::FileExists(fullPathScriptName))
903 // =============================================================== iterate on the paths
906 std::vector<std::string>::iterator i;
907 for (i=script_paths.begin();i!=script_paths.end();++i)
911 // we *really* want '.' to be the current working directory
913 char buf[2048]; // for getcwd
914 char * currentDir = getcwd(buf, 2048);
915 std::string cwd(currentDir);
919 // fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true); //pkgname);
921 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
924 // Check if library exists
925 if ( ! Utilities::FileExists(fullPathScriptName) )
927 // The following is *NOT* a debug time message :
928 // It's a user intended message.
929 // Please don't remove it.
930 bbtkMessage("Interpreter",2,
931 " [" <<fullPathScriptName <<"] : doesn't exist"
933 continue; // try next path
935 bbtkMessage("Interpreter",2,
936 " [" <<fullPathScriptName
937 <<"] : found" <<std::endl);
939 break; // a script was found; we stop iterating
941 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
947 if(fullPathScriptName == "")
948 bbtkError("Path ["<<upath<<"] doesn't exist");
950 bbtkError("Script ["<<fullPathScriptName<<"] not found");
952 bbtkError("No ["<<pkgname<<".bbs] script found");
956 LoadScript(fullPathScriptName,name);
962 //=======================================================================
964 void Interpreter::LoadScript( std::string fullPathScriptName,
965 std::string includeScriptName)
967 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)
970 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
971 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
976 s = new std::ifstream;
977 s->open(fullPathScriptName.c_str());
980 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
984 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
985 << "] found" << std::endl);
988 mFileName.push_back(fullPathScriptName);
989 mIncludeFileName.push_back(includeScriptName);
994 //=======================================================================
998 void Interpreter::CloseCurrentFile()
1000 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1003 if (mFile.size()==0)
1005 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1009 mFile.back()->close();
1010 delete mFile.back();
1012 bbtkDebugMessage("Interpreter",9,
1013 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1015 mFileName.pop_back();
1016 mIncludeFileName.pop_back();
1018 bbtkDebugMessage("Interpreter",9," Remains "
1020 <<" open"<<std::endl);
1021 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1024 //=======================================================================
1026 //=======================================================================
1030 void Interpreter::CloseAllFiles()
1032 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1035 while (mFile.size() != 0)
1037 mFile.back()->close();
1038 delete mFile.back();
1040 bbtkDebugMessage("Interpreter",9,
1041 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1042 mFileName.pop_back();
1043 mIncludeFileName.pop_back();
1046 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1049 //=======================================================================
1053 //=======================================================================
1057 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1058 CommandInfoType& info )
1060 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1062 // searches the command category
1063 CommandDictType::iterator c;
1064 c = mCommandDict.find(words[0]);
1065 if ( c == mCommandDict.end() ) {
1066 bbtkError(words[0]<<" : unknown command");
1069 // tests the number of args
1070 if ( ( words.size()-1 < c->second.argmin ) ||
1071 ( words.size()-1 > c->second.argmax ) )
1073 HelpCommand(words[0]);
1074 bbtkError(words[0]<<" : wrong number of arguments");
1078 bbtkDecTab("Interpreter",9);
1080 //=======================================================================
1083 //=======================================================================
1084 /// Displays help on all the commands
1085 void Interpreter::Help(const std::vector<std::string>& words)
1087 unsigned int nbarg = words.size()-1;
1095 if (words[1]=="packages")
1097 GetExecuter()->GetFactory()->PrintPackages(true);
1102 HelpCommand(words[1]);
1104 catch (bbtk::Exception e)
1108 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1109 #ifdef _USE_WXWIDGETS_
1110 if ( mWxConsole != 0 )
1113 ConfigurationFile::GetInstance().Get_doc_path();
1114 url += "/bbdoc/" + words[1] + "/index.html";
1115 if (Utilities::FileExists(url))
1117 mWxConsole->ShowHtmlPage(url);
1122 catch (bbtk::Exception f)
1126 std::string package;
1127 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1128 #ifdef _USE_WXWIDGETS_
1129 if ( mWxConsole != 0 )
1132 ConfigurationFile::GetInstance().Get_doc_path();
1133 url += "/bbdoc/" + package + "/index.html";
1134 if (Utilities::FileExists(url))
1136 url += "#" + words[1];
1137 mWxConsole->ShowHtmlPage(url);
1142 catch (bbtk::Exception g)
1146 GetExecuter()->ShowRelations(words[1],"0","9999");
1148 catch (bbtk::Exception h){
1149 bbtkError("\""<<words[1].c_str()
1150 <<"\" is not a known command, package, black box type or black box name");
1158 if (words[2]=="all")
1160 if ( words[1]=="packages" )
1162 GetExecuter()->GetFactory()->PrintPackages(true,true);
1167 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1169 catch (bbtk::Exception f)
1175 HelpCommand(words[0]);
1176 bbtkError(words[0]<<" : syntax error");
1181 bbtkError("Should not reach here !!!");
1184 //=======================================================================
1186 //===================================================================
1187 /// Displays the Configuration
1188 void Interpreter::Config() const
1190 ConfigurationFile::GetInstance().GetHelp(1);
1192 //===================================================================
1194 //=======================================================================
1195 /// Displays help on all the commands
1196 void Interpreter::HelpCommands()
1198 std::cout << "Available commands :" << std::endl;
1199 CommandDictType::iterator i;
1200 for ( i = mCommandDict.begin();
1201 i != mCommandDict.end();
1203 std::cout << " " << i->first << std::endl;
1204 // std::cout << " usage : " << i->second.syntax << std::endl;
1205 // std::cout << " " << i->second.help << std::endl;
1209 //=======================================================================
1212 //=======================================================================
1213 /// Displays help on a particular commands
1214 void Interpreter::HelpCommand(const std::string& s)
1216 CommandDictType::iterator c;
1217 c = mCommandDict.find(s);
1218 if ( c == mCommandDict.end() ) {
1219 bbtkError(s<<" : Unknown command");
1221 // std::cout << " " << s << " : "<< std::endl;
1222 // CommandParamDictType::iterator i;
1223 // for ( i = c->second.begin();
1224 // i != c->second.end();
1226 std::cout << " usage : " << c->second.syntax << std::endl;
1227 std::cout << " " << c->second.help << std::endl;
1230 //=======================================================================
1233 //=======================================================================
1234 /// Fills the vector commands with the commands which
1235 /// have the first n chars of buf for prefix
1236 /// TODO : skip initial spaces in buf and also return the position of first
1237 /// non blank char in buf
1238 void Interpreter::FindCommandsWithPrefix( char* buf,
1240 std::vector<std::string>& commands )
1242 CommandDictType::const_iterator i;
1243 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1245 if ((i->first).find(buf,0,n) == 0)
1246 commands.push_back(i->first);
1249 //=======================================================================
1253 //=======================================================================
1254 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1256 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1257 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1259 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1260 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1261 // E.G. STORE THIS IN bbtk_config.xml
1262 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1263 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1264 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1265 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1266 #define BBTK_BACKSPACE_KBCODE 0x00000008
1267 #define BBTK_DEL_KBCODE 0x0000007F
1268 #define BBTK_SPACE_KBCODE 0x00000020
1270 //=======================================================================
1271 void Interpreter::GetLineFromPrompt(std::string& s)
1276 int MAX_LINE_SIZE = 160;
1277 int MAX_HISTORY_SIZE = 100;
1279 char* newline = new char[MAX_LINE_SIZE];
1280 memset(newline,0,MAX_LINE_SIZE);
1281 char* histline = new char[MAX_LINE_SIZE];
1282 memset(histline,0,MAX_LINE_SIZE);
1284 char* line = newline;
1285 int hist = mHistory.size();
1291 read ( STDIN_FILENO, &c, 4) ;
1293 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1295 // Printable character
1296 if ( (ind<MAX_LINE_SIZE-1) &&
1297 ( c >= BBTK_SPACE_KBCODE ) &&
1298 ( c < BBTK_DEL_KBCODE ))
1306 // delete the unused line
1312 // empty lines are not stored in from history
1315 // if history too long : delete oldest command
1316 if (mHistory.size()>MAX_HISTORY_SIZE)
1318 delete mHistory.front();
1319 mHistory.pop_front();
1321 mHistory.push_back(line);
1326 else if ( (ind>0) &&
1327 ((c == BBTK_BACKSPACE_KBCODE) ||
1328 (c == BBTK_DEL_KBCODE)) )
1336 // TODO : Command completion
1337 std::vector<std::string> commands;
1338 FindCommandsWithPrefix( line,ind,commands);
1339 if (commands.size()==1)
1341 std::string com = *commands.begin();
1342 for (; ind<com.size(); ++ind)
1344 PrintChar(com[ind]);
1350 else if (commands.size()>1)
1352 std::vector<std::string>::iterator i;
1354 for (i=commands.begin();i!=commands.end();++i)
1356 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1359 write(STDOUT_FILENO,"\n> ",3);
1360 //for (int j=0;j<ind;++j)
1362 write(STDOUT_FILENO,line,ind);
1366 // Arrow up : back in history
1367 else if (c==BBTK_UP_ARROW_KBCODE)
1371 // erase current line
1372 while (ind--) BackSpace();
1376 strcpy(histline,mHistory[hist]);
1380 write(STDOUT_FILENO,line,ind);
1383 // Arrow down : down in history
1384 else if (c==BBTK_DOWN_ARROW_KBCODE)
1386 if (hist<mHistory.size()-1)
1388 // erase current line
1389 while (ind--) BackSpace();
1393 strcpy(histline,mHistory[hist]);
1397 write(STDOUT_FILENO,line,ind);
1399 // end of history : switch back to newline
1400 else if (hist==mHistory.size()-1)
1402 // erase current line
1403 while (ind--) BackSpace();
1410 write(STDOUT_FILENO,line,ind);
1414 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1416 PrintChar(line[ind]);
1421 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1429 write(STDOUT_FILENO,"\n\r",2);
1437 //=======================================================================
1438 void Interpreter::GetLineFromPrompt(std::string& s)
1464 //=======================================================================
1470 //=======================================================================
1471 void Interpreter::CommandLineInterpreter()
1473 bbtkDebugMessageInc("Interpreter",9,
1474 "Interpreter::CommandLineInterpreter()"<<std::endl);
1476 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1477 // Initialise the tty in non canonical mode with no echo
1478 // oter remembers the previous settings to restore them after
1479 struct termios ter,oter;
1482 ter.c_lflag &= ~ECHO;
1483 ter.c_lflag &= ~ICANON;
1486 tcsetattr(0,TCSANOW,&ter);
1489 mCommandLine = true;
1491 bool insideComment = false; // for multiline comment
1497 GetLineFromPrompt(line);
1498 InterpretLine(line, insideComment);
1500 catch (QuitException e)
1504 catch (bbtk::Exception e)
1508 catch (std::exception& e)
1510 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1514 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1519 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1520 tcsetattr(0,TCSANOW,&oter);
1523 std::cout << "Good bye !" << std::endl;
1525 bbtkDebugDecTab("Interpreter",9);
1528 //=======================================================================
1529 void Interpreter::Graph(const std::vector<std::string>& words)
1532 bool system_display = true;
1534 #ifdef _USE_WXWIDGETS_
1535 if ( mWxConsole != 0 ) system_display = false;
1538 if (words.size()==1)
1540 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1542 else if (words.size()==2)
1544 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1546 else if (words.size()==3)
1548 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1550 else if (words.size()==4)
1552 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1554 else if (words.size()==5)
1556 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1558 else if (words.size()==6)
1560 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1562 else if (words.size()==7)
1564 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1567 #ifdef _USE_WXWIDGETS_
1568 if ( mWxConsole != 0 )
1569 mWxConsole->ShowHtmlPage(page);
1572 //=======================================================================
1575 //=======================================================================
1576 void Interpreter::Index(const std::string& filename,
1577 const std::string& type)
1579 Factory::IndexEntryType t;
1580 if (type=="Initials") t = Factory::Initials;
1581 else if (type=="Categories") t = Factory::Categories;
1582 else if (type=="Packages") t = Factory::Packages;
1583 else if (type=="Adaptors") t = Factory::Adaptors;
1585 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1587 //=======================================================================