1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/02/06 10:53:02 $
7 Version: $Revision: 1.28 $
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
39 Interpreter* Interpreter::mGlobalInterpreter = NULL;
41 //=======================================================================
45 Interpreter::Interpreter()
49 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
50 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
51 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
53 mGlobalInterpreter = this;
55 // mFactory = new bbtk::Factory();
56 mExecuter = new bbtk::Executer();
57 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
58 //mExecuter->SetFactory(mFactory);
60 // Builds the commands dict
63 info.category = "new";
67 info.syntax = "new <type> <name>";
68 info.help = "Creates a new black box of type <type> with name <name>";
69 mCommandDict[info.category] = info;
71 info.category = "delete";
75 info.syntax = "delete <box>";
76 info.help = "Deletes the black box of name <box>";
77 mCommandDict[info.category] = info;
79 info.category = "connect";
83 info.syntax = "connect <box1.output> <box2.input>";
84 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
85 mCommandDict[info.category] = info;
87 info.category = "print";
91 info.syntax = "print <string>";
92 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').";
93 mCommandDict[info.category] = info;
95 info.category = "exec";
99 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
100 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.";
101 mCommandDict[info.category] = info;
103 info.category = "package";
106 info.code = cPackage;
107 info.syntax = "package <name>";
108 info.help = "Begins the definition of a package.";
109 mCommandDict[info.category] = info;
111 info.category = "endpackage";
114 info.code = cEndPackage;
115 info.syntax = "endpackage";
116 info.help = "Ends the definition of a package.";
117 mCommandDict[info.category] = info;
119 info.category = "define";
123 info.syntax = "define <type> [<package>]";
124 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.";
125 mCommandDict[info.category] = info;
127 info.category = "endefine";
130 info.code = cEndDefine;
131 info.syntax = "endefine";
132 info.help = "Ends the definition of a new type of complex black box";
133 mCommandDict[info.category] = info;
135 info.category = "input";
139 info.syntax = "input <name> <box.input> <help>";
140 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";
141 mCommandDict[info.category] = info;
143 info.category = "output";
147 info.syntax = "output <name> <box.output> <help>";
148 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";
149 mCommandDict[info.category] = info;
151 info.category = "set";
155 info.syntax = "set <box.input> <value>";
156 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";
157 mCommandDict[info.category] = info;
159 info.category = "config"; // JPR
163 info.syntax = "config";
164 info.help = "Prints the value of all configuration parameters";
165 mCommandDict[info.category] = info;
167 info.category = "index"; // LG
172 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories']]";
173 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";
174 mCommandDict[info.category] = info;
176 info.category = "reset"; //EED
180 info.syntax = "reset";
181 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
182 mCommandDict[info.category] = info;
184 info.category = "author";
188 info.syntax = "author <string>";
189 info.help = "Adds the string <string> to the author information of the black box being defined";
190 mCommandDict[info.category] = info;
192 info.category = "category"; //JP
195 info.code = cCategory;
196 info.syntax = "category <list of items, separated by ;>";
197 info.help = "Adds the string <string> to the category information of the black box being defined";
198 mCommandDict[info.category] = info;
200 info.category = "description";
203 info.code = cDescription;
204 info.syntax = "description <string>";
205 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
206 mCommandDict[info.category] = info;
208 info.category = "help";
212 info.syntax = "help";
213 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>";
214 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.";
215 mCommandDict[info.category] = info;
217 info.category = "message";
220 info.code = cMessage;
221 info.syntax = "message <kind> <level>";
222 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;
224 info.category = "include";
227 info.code = cInclude;
228 info.syntax = "include <filename> [source]";
229 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).";
230 mCommandDict[info.category] = info;
232 info.category = "quit";
236 info.syntax = "quit";
237 info.help = "Quits the program (during script execution it stops the complete execution)";
238 mCommandDict[info.category] = info;
240 info.category = "load";
244 info.syntax = "load <packagename>";
245 info.help = "Loads the black box package <packagename>";
246 mCommandDict[info.category] = info;
248 info.category = "unload";
252 info.syntax = "unload <packagename>";
253 info.help = "Unloads the black box package <packagename>";
254 mCommandDict[info.category] = info;
256 info.category = "graph";
260 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 ]]]]]]";
261 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')";
262 mCommandDict[info.category] = info;
265 info.category = "workspace";
268 info.code = cWorkspace;
269 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
270 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.";
271 mCommandDict[info.category] = info;
274 bbtkDebugDecTab("Interpreter",9);
277 //=======================================================================
281 //=======================================================================
285 Interpreter::~Interpreter()
287 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
291 bbtkDebugDecTab("Interpreter",9);
293 //=======================================================================
296 //=======================================================================
300 void Interpreter::InterpretFile( const std::string& filename,
301 bool use_configuration_file)
303 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
305 bool exm = mCommandLine;
306 mCommandLine = false;
310 SwitchToFile(filename, use_configuration_file);
311 bool insideComment = false; // for multiline comment
312 while (mFile.size()>0)
314 while ((mFile.size()>0) &&
315 (!mFile.back()->eof()))
319 mFile.back()->getline(buf,500);
321 std::string str(buf);
322 int size=str.length();
323 if ( str[ size-1 ]==13 )
328 InterpretLine(str, insideComment);
330 //if (mFile.size()>0)
334 catch (QuitException e)
337 catch (bbtk::Exception e)
339 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
340 if (mFileName.size()) {
341 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
342 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
345 catch (std::exception& e)
347 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
348 if (mFileName.size()) {
349 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
350 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
355 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
356 if (mFileName.size()) {
357 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
358 std::cout << "* LINE : "<<mLine.back()<<std::endl;
363 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
364 bbtkDecTab("Interpreter",9);
368 //=======================================================================
372 //=======================================================================
376 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
379 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
380 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
382 std::vector<std::string> words;
383 SplitLine(line,words);
388 bbtkDebugDecTab("Interpreter",9);
392 // Single line comment : # or //
393 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
395 bbtkDebugDecTab("Interpreter",9);
396 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
400 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
402 if (words[0][0]=='/' && words[0][1]=='*')
404 bbtkDebugDecTab("Interpreter",9);
405 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
406 insideComment = true;
410 if (words[0][0]=='*' && words[0][1]=='/')
412 bbtkDebugDecTab("Interpreter",9);
413 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
414 if ( !insideComment ) {
415 bbtkDebugDecTab("Interpreter",9);
416 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
418 insideComment = false;
424 bbtkDebugDecTab("Interpreter",9);
425 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
430 CommandInfoType command;
431 InterpretCommand(words,command);
433 bbtkDebugMessage("Interpreter",9,
434 "Command='"<<command.category
435 <<"' code="<<command.code<<std::endl);
437 std::string left,right,left2,right2;
438 std::string filename;
439 switch (command.code)
442 mExecuter->Create(words[1],words[2]);
447 // mExecuter->Remove(words[1]);
451 Utilities::SplitAroundFirstDot(words[1],left,right);
452 Utilities::SplitAroundFirstDot(words[2],left2,right2);
453 mExecuter->Connect(left,right,left2,right2);
457 mExecuter->BeginPackage(words[1]);
461 mExecuter->EndPackage();
465 if (mFileName.size()>0)
467 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
471 mExecuter->Define(words[1],"",filename);
475 mExecuter->Define(words[1],words[2],filename);
480 mExecuter->EndDefine();
484 Print(words[1]); /// \todo use mExecuter
488 if (words[1]=="freeze")
489 mExecuter->SetNoExecMode(true);
490 else if (words[1]=="unfreeze")
491 mExecuter->SetNoExecMode(false);
493 mExecuter->Update(words[1]);
497 Utilities::SplitAroundFirstDot(words[2],left,right);
498 mExecuter->DefineInput(words[1],left,right,words[3]);
502 Utilities::SplitAroundFirstDot(words[2],left,right);
503 mExecuter->DefineOutput(words[1],left,right,words[3]);
507 Utilities::SplitAroundFirstDot(words[1],left,right);
508 mExecuter->Set(left,right,words[2]);
512 mExecuter->Author(words[1]);
516 mExecuter->Category(words[1]);
521 Index("tmp_index.html");
522 else if (words.size()==2)
524 else if (words.size()==3)
525 Index(words[1],words[2]);
528 mExecuter->Description(words[1]);
538 bbtk::MessageManager::PrintInfo();
542 sscanf(words[2].c_str(),"%d",&level);
543 bbtk::MessageManager::SetMessageLevel(words[1],level);
556 this->mExecuter->Reset();
562 InterpretFile(words[1], true ); // true : better pass use_config_file
566 SwitchToFile(words[1], true ); // true : better pass use_config_file
568 // if 'source' was given
571 this->mExecuter->SetCurrentFileName(words[1]);
576 LoadPackage(words[1], true ); // true : better pass use_config_file
580 UnLoadPackage(words[1]);
584 throw QuitException();
588 if (words.size() == 2)
590 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
591 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
595 mExecuter->SetWorkspaceName(words[2]);
600 bbtkInternalError("should not reach here !!!");
603 bbtkDecTab("Interpreter",9);
605 //=======================================================================
611 //=======================================================================
615 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
617 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
619 std::string delimiters = "\"";
620 std::vector<std::string> quote;
621 Utilities::SplitString(str,delimiters,quote);
624 std::vector<std::string>::iterator i;
625 for (i=quote.begin(); i!=quote.end(); )
627 Utilities::SplitString(*i,delimiters,tokens);
631 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
632 tokens.push_back(*i);
637 for (i=tokens.begin(); i!=tokens.end(); ++i)
639 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
641 bbtkDebugMessageCont("Interpreter",9,std::endl);
643 bbtkDebugDecTab("Interpreter",9);
645 //=======================================================================
648 //=======================================================================
649 // Replaces substrings "\\n" by a real carriage return "\n"
650 void SubsBackslashN ( std::string& s )
652 std::string ss("\\n");
653 std::string::size_type pos = 0;
656 while ( pos != std::string::npos )
658 s.replace(pos,2,cr,1);
659 pos = s.find(ss, pos-1);
662 //=======================================================================
665 //=======================================================================
669 void Interpreter::Print( const std::string& str)
671 if (mExecuter->GetNoExecMode()) return;
673 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
675 std::vector<std::string> chains;
676 std::string delimiters("$");
678 // Skip delimiters at beginning.
679 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
681 if (lastPos>0) is_text = false;
683 // Find first delimiter.
684 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
686 while (std::string::npos != pos || std::string::npos != lastPos)
690 // Found a text token, add it to the vector.
691 chains.push_back(str.substr(lastPos, pos - lastPos));
695 // is an output (between $$) : decode
696 std::string tok,box,output;
697 tok = str.substr(lastPos, pos - lastPos);
698 Utilities::SplitAroundFirstDot(tok,box,output);
699 chains.push_back( mExecuter->Get(box,output) );
701 // Skip delimiters. Note the "not_of"
702 lastPos = str.find_first_not_of(delimiters, pos);
703 // Find next delimiter
704 pos = str.find_first_of(delimiters, lastPos);
708 std::vector<std::string>::iterator i;
709 for (i= chains.begin(); i!=chains.end(); ++i)
711 // bbtkMessage("Echo",1,*i);
715 std::cout << std::endl;
716 bbtkDebugDecTab("Interpreter",9);
719 //=======================================================================
724 // ===================================================================================
726 void Interpreter::SwitchToFile( const std::string& name,
727 bool use_configuration_file )
729 // Note : in the following :
730 // name : the user supplied name
731 // - abreviated name e.g. scr scr.bbs
732 // - relative full name e.g. ./scr.bbs ../../scr.bbs
733 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
734 // same for Windows, with c:, d: ...
736 // use ./directory/subdir/scrname.bbs
739 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
740 <<name<<"\")"<<std::endl);
742 std::vector<std::string> script_paths;
743 std::string fullPathScriptName; // full path script name
744 std::string pkgname; // e.g. <scriptname>.bbs
745 std::vector<std::string> Filenames;
747 if (use_configuration_file)
749 // The following is *NOT* a debug time message :
750 // It's a user intended message.
751 // Please don't remove it.
752 bbtkMessage("Interpreter",1,
753 "look for : [" << name
754 << "] (use_configuration_file == TRUE)" << std::endl);
755 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
758 pkgname = Utilities::ExtractScriptName(name,upath);
760 bool fullnameGiven = false;
761 bool foundFile = false;
763 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
767 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
769 int nbFiles = Utilities::Explore(upath, false, Filenames);
771 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
773 if ((*i).substr((*i).size()-4, 4) != ".bbs")
774 continue; // ignore non .bbs files
779 bbtkMessage("Interpreter",2,
780 "WARNING : No '.bbs' file found in ["
781 << upath << "]" << std::endl);
788 std::vector<std::string>::iterator i;
789 std::string fullDirectoryName;
790 for (i=script_paths.begin();i!=script_paths.end();++i)// ==== relative name, iterate + load all .bbs files
794 // we *really* want '.' to be the current working directory
796 char buf[2048]; // for getcwd
797 char * currentDir = getcwd(buf, 2048);
798 std::string cwd(currentDir);
802 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
804 // Check if library exists
805 if ( ! Utilities::IsDirectory(fullDirectoryName) )
807 // The following is *NOT* a debug time message :
808 // It's a user intended message.
809 // Please don't remove it.
810 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
811 <<"] : doesn't exist" <<std::endl);
812 continue; // try next path
817 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
820 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
823 if ((*i).substr((*i).size()-4, 4) != ".bbs")
824 continue; // ignore non .bbs files
829 bbtkMessage("Interpreter",1,
830 "WARNING : No '.bbs' file found in ["
831 << fullDirectoryName << "]" << std::endl);
833 //break; // a directory was found; we stop iterating
834 // LG : No! We want all files included !
839 //std::string::size_type slash_position = name.find_last_of("/\\");
841 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
842 // (not only a plain script name)
843 // we trust him, and try to expland the directory name
844 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
846 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
849 // ===========================================================check user supplied location
850 fullnameGiven = true;
853 fullPathScriptName = Utilities::ExpandLibName(name, false);
855 // allow user to always forget ".bbs"
856 int l = fullPathScriptName.size();
862 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
864 fullPathScriptName = fullPathScriptName + ".bbs";
869 fullPathScriptName = fullPathScriptName + ".bbs";
872 if ( Utilities::FileExists(fullPathScriptName))
880 // =============================================================== iterate on the paths
883 std::vector<std::string>::iterator i;
884 for (i=script_paths.begin();i!=script_paths.end();++i)
888 // we *really* want '.' to be the current working directory
890 char buf[2048]; // for getcwd
891 char * currentDir = getcwd(buf, 2048);
892 std::string cwd(currentDir);
896 // fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true); //pkgname);
898 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
901 // Check if library exists
902 if ( ! Utilities::FileExists(fullPathScriptName) )
904 // The following is *NOT* a debug time message :
905 // It's a user intended message.
906 // Please don't remove it.
907 bbtkMessage("Interpreter",2,
908 " [" <<fullPathScriptName <<"] : doesn't exist"
910 continue; // try next path
912 bbtkMessage("Interpreter",2,
913 " [" <<fullPathScriptName
914 <<"] : found" <<std::endl);
916 break; // a script was found; we stop iterating
918 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
924 if(fullPathScriptName == "")
925 bbtkError("Path ["<<upath<<"] doesn't exist");
927 bbtkError("Script ["<<fullPathScriptName<<"] not found");
929 bbtkError("No ["<<pkgname<<".bbs] script found");
933 LoadScript(fullPathScriptName,name);
939 //=======================================================================
941 void Interpreter::LoadScript( std::string fullPathScriptName,
942 std::string includeScriptName)
944 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)
947 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
948 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
953 s = new std::ifstream;
954 s->open(fullPathScriptName.c_str());
957 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
961 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
962 << "] found" << std::endl);
965 mFileName.push_back(fullPathScriptName);
966 mIncludeFileName.push_back(includeScriptName);
971 //=======================================================================
975 void Interpreter::CloseCurrentFile()
977 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
982 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
986 mFile.back()->close();
989 bbtkDebugMessage("Interpreter",9,
990 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
992 mFileName.pop_back();
993 mIncludeFileName.pop_back();
995 bbtkDebugMessage("Interpreter",9," Remains "
997 <<" open"<<std::endl);
998 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1001 //=======================================================================
1003 //=======================================================================
1007 void Interpreter::CloseAllFiles()
1009 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1012 while (mFile.size() != 0)
1014 mFile.back()->close();
1015 delete mFile.back();
1017 bbtkDebugMessage("Interpreter",9,
1018 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1019 mFileName.pop_back();
1020 mIncludeFileName.pop_back();
1023 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1026 //=======================================================================
1030 //=======================================================================
1034 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1035 CommandInfoType& info )
1037 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1039 // searches the command category
1040 CommandDictType::iterator c;
1041 c = mCommandDict.find(words[0]);
1042 if ( c == mCommandDict.end() ) {
1043 bbtkError(words[0]<<" : unknown command");
1046 // tests the number of args
1047 if ( ( words.size()-1 < c->second.argmin ) ||
1048 ( words.size()-1 > c->second.argmax ) )
1050 HelpCommand(words[0]);
1051 bbtkError(words[0]<<" : wrong number of arguments");
1055 bbtkDecTab("Interpreter",9);
1057 //=======================================================================
1060 //=======================================================================
1061 /// Displays help on all the commands
1062 void Interpreter::Help(const std::vector<std::string>& words)
1064 unsigned int nbarg = words.size()-1;
1072 if (words[1]=="packages")
1074 PrintPackages(true);
1079 HelpCommand(words[1]);
1081 catch (bbtk::Exception e)
1085 HelpPackage(words[1]);
1087 catch (bbtk::Exception f)
1091 HelpBlackBox(words[1]);
1093 catch (bbtk::Exception g)
1097 this->mExecuter->ShowRelations(words[1],"0","9999");
1099 catch (bbtk::Exception h){
1100 bbtkError("\""<<words[1].c_str()
1101 <<"\" is not a known command, package, black box type or black box name");
1109 if (words[2]=="all")
1111 if ( words[1]=="packages" )
1113 PrintPackages(true,true);
1118 HelpPackage(words[1],true);
1120 catch (bbtk::Exception f)
1126 HelpCommand(words[0]);
1127 bbtkError(words[0]<<" : syntax error");
1132 bbtkError("Should not reach here !!!");
1135 //=======================================================================
1137 //===================================================================
1138 /// Displays the Configuration
1139 void Interpreter::Config() const
1141 bbtkDebugMessageInc("Kernel",9,"Factory::Config"<<std::endl);
1143 ConfigurationFile cf = ConfigurationFile::GetInstance();
1145 const std::string config_xml_full_path = cf.Get_config_xml_full_path();
1146 const std::string description = cf.Get_description();
1147 const std::string url = cf.Get_url();
1148 const std::string data_path = cf.Get_data_path();
1149 const std::string default_temp_dir = cf.Get_default_temp_dir();
1150 const std::string file_separator = cf.Get_file_separator();
1151 const std::vector<std::string>bbs_paths = cf.Get_bbs_paths();
1152 const std::vector<std::string>package_paths = cf.Get_package_paths();
1154 bbtkMessage("Help",1, "=============" << std::endl);
1155 bbtkMessage("Help",1, "Configuration" << std::endl);
1156 bbtkMessage("Help",1, "=============" << std::endl);
1157 bbtkMessage("Help",1, "bbtk_config.xml : [" << config_xml_full_path << "]" << std::endl);
1158 bbtkMessage("Help",1, "Documentation Url : [" << url << "]" << std::endl);
1159 bbtkMessage("Help",1, "Data Path : [" << data_path << "]" << std::endl);
1160 bbtkMessage("Help",1, "Default Temp-Dir : [" << default_temp_dir << "]" << std::endl);
1161 bbtkMessage("Help",1, "File Separator : [" << file_separator << "]" << std::endl);
1163 std::vector<std::string>::const_iterator i;
1165 bbtkMessage("Help",1, "BBS Paths " << std::endl);
1166 for (i = bbs_paths.begin(); i!=bbs_paths.end(); ++i )
1168 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1171 bbtkMessage("Help",1, "PACKAGE Paths : " << std::endl);
1172 for (i = package_paths.begin(); i!=package_paths.end(); ++i )
1174 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1177 bbtkDebugDecTab("Kernel",9);
1180 //=======================================================================
1181 /// Displays help on all the commands
1182 void Interpreter::HelpCommands()
1184 std::cout << "Available commands :" << std::endl;
1185 CommandDictType::iterator i;
1186 for ( i = mCommandDict.begin();
1187 i != mCommandDict.end();
1189 std::cout << " " << i->first << std::endl;
1190 // std::cout << " usage : " << i->second.syntax << std::endl;
1191 // std::cout << " " << i->second.help << std::endl;
1195 //=======================================================================
1198 //=======================================================================
1199 /// Displays help on a particular commands
1200 void Interpreter::HelpCommand(const std::string& s)
1202 CommandDictType::iterator c;
1203 c = mCommandDict.find(s);
1204 if ( c == mCommandDict.end() ) {
1205 bbtkError(s<<" : Unknown command");
1207 // std::cout << " " << s << " : "<< std::endl;
1208 // CommandParamDictType::iterator i;
1209 // for ( i = c->second.begin();
1210 // i != c->second.end();
1212 std::cout << " usage : " << c->second.syntax << std::endl;
1213 std::cout << " " << c->second.help << std::endl;
1216 //=======================================================================
1219 //=======================================================================
1220 /// Fills the vector commands with the commands which
1221 /// have the first n chars of buf for prefix
1222 /// TODO : skip initial spaces in buf and also return the position of first
1223 /// non blank char in buf
1224 void Interpreter::FindCommandsWithPrefix( char* buf,
1226 std::vector<std::string>& commands )
1228 CommandDictType::const_iterator i;
1229 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1231 if ((i->first).find(buf,0,n) == 0)
1232 commands.push_back(i->first);
1235 //=======================================================================
1239 //=======================================================================
1240 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1242 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1243 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1245 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1246 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1247 // E.G. STORE THIS IN bbtk_config.xml
1248 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1249 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1250 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1251 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1252 #define BBTK_BACKSPACE_KBCODE 0x00000008
1253 #define BBTK_DEL_KBCODE 0x0000007F
1254 #define BBTK_SPACE_KBCODE 0x00000020
1256 //=======================================================================
1257 void Interpreter::GetLineFromPrompt(std::string& s)
1262 int MAX_LINE_SIZE = 160;
1263 int MAX_HISTORY_SIZE = 100;
1265 char* newline = new char[MAX_LINE_SIZE];
1266 memset(newline,0,MAX_LINE_SIZE);
1267 char* histline = new char[MAX_LINE_SIZE];
1268 memset(histline,0,MAX_LINE_SIZE);
1270 char* line = newline;
1271 int hist = mHistory.size();
1278 read ( STDIN_FILENO, &c, 4) ;
1280 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1282 // Printable character
1283 if ( (ind<MAX_LINE_SIZE-1) &&
1284 ( c >= BBTK_SPACE_KBCODE ) &&
1285 ( c < BBTK_DEL_KBCODE ))
1293 // delete the unused line
1299 // empty lines are not stored in from history
1302 // if history too long : delete oldest command
1303 if (mHistory.size()>MAX_HISTORY_SIZE)
1305 delete mHistory.front();
1306 mHistory.pop_front();
1308 mHistory.push_back(line);
1313 else if ( (ind>0) &&
1314 ((c == BBTK_BACKSPACE_KBCODE) ||
1315 (c == BBTK_DEL_KBCODE)) )
1323 // TODO : Command completion
1324 std::vector<std::string> commands;
1325 FindCommandsWithPrefix( line,ind,commands);
1326 if (commands.size()==1)
1328 std::string com = *commands.begin();
1329 for (; ind<com.size(); ++ind)
1331 PrintChar(com[ind]);
1337 else if (commands.size()>1)
1339 std::vector<std::string>::iterator i;
1341 for (i=commands.begin();i!=commands.end();++i)
1343 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1346 write(STDOUT_FILENO,"\n> ",3);
1347 //for (int j=0;j<ind;++j)
1349 write(STDOUT_FILENO,line,ind);
1353 // Arrow up : back in history
1354 else if (c==BBTK_UP_ARROW_KBCODE)
1358 // erase current line
1359 while (ind--) BackSpace();
1363 strcpy(histline,mHistory[hist]);
1367 write(STDOUT_FILENO,line,ind);
1370 // Arrow down : down in history
1371 else if (c==BBTK_DOWN_ARROW_KBCODE)
1373 if (hist<mHistory.size()-1)
1375 // erase current line
1376 while (ind--) BackSpace();
1380 strcpy(histline,mHistory[hist]);
1384 write(STDOUT_FILENO,line,ind);
1386 // end of history : switch back to newline
1387 else if (hist==mHistory.size()-1)
1389 // erase current line
1390 while (ind--) BackSpace();
1397 write(STDOUT_FILENO,line,ind);
1401 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1403 PrintChar(line[ind]);
1408 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1416 write(STDOUT_FILENO,"\n\r",2);
1424 //=======================================================================
1425 void Interpreter::GetLineFromPrompt(std::string& s)
1451 //=======================================================================
1457 //=======================================================================
1458 void Interpreter::CommandLineInterpreter()
1460 bbtkDebugMessageInc("Interpreter",9,
1461 "Interpreter::CommandLineInterpreter()"<<std::endl);
1463 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1464 // Initialise the tty in non canonical mode with no echo
1465 // oter remembers the previous settings to restore them after
1466 struct termios ter,oter;
1469 ter.c_lflag &= ~ECHO;
1470 ter.c_lflag &= ~ICANON;
1473 tcsetattr(0,TCSANOW,&ter);
1476 mCommandLine = true;
1478 bool insideComment = false; // for multiline comment
1484 GetLineFromPrompt(line);
1485 InterpretLine(line, insideComment);
1487 catch (QuitException e)
1491 catch (bbtk::Exception e)
1495 catch (std::exception& e)
1497 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1501 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1506 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1507 tcsetattr(0,TCSANOW,&oter);
1510 std::cout << "Good bye !" << std::endl;
1512 bbtkDebugDecTab("Interpreter",9);
1515 //=======================================================================
1516 void Interpreter::Graph(const std::vector<std::string>& words)
1519 bool system_display = true;
1521 #ifdef _USE_WXWIDGETS_
1522 if ( WxConsole::GetInstance() != 0 ) system_display = false;
1525 if (words.size()==1)
1527 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1529 else if (words.size()==2)
1531 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1533 else if (words.size()==3)
1535 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1537 else if (words.size()==4)
1539 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1541 else if (words.size()==5)
1543 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1545 else if (words.size()==6)
1547 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1549 else if (words.size()==7)
1551 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1554 #ifdef _USE_WXWIDGETS_
1555 if ( WxConsole::GetInstance() != 0 )
1556 WxConsole::GetInstance()->ShowHtmlPage(page);
1559 //=======================================================================
1562 //=======================================================================
1563 void Interpreter::Index(const std::string& filename,
1564 const std::string& type)
1566 Factory::IndexEntryType t;
1567 if (type=="Initials") t = Factory::Initials;
1568 else if (type=="Categories") t = Factory::Categories;
1569 else if (type=="Packages") t = Factory::Packages;
1571 GetGlobalFactory()->CreateHtmlIndex(t,filename);
1573 //=======================================================================