1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/02/04 13:51:30 $
7 Version: $Revision: 1.19 $
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()
47 mCommandLine(false), verbose(false)
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->SetFactory(mFactory);
59 // Builds the commands dict
66 info.syntax = "new <type> <name>";
67 info.help = "Creates a new black box of type <type> with name <name>";
68 mCommandDict[info.keyword] = info;
70 info.keyword = "delete";
74 info.syntax = "delete <box>";
75 info.help = "Deletes the black box of name <box>";
76 mCommandDict[info.keyword] = info;
78 info.keyword = "connect";
82 info.syntax = "connect <box1.output> <box2.input>";
83 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
84 mCommandDict[info.keyword] = info;
86 info.keyword = "print";
90 info.syntax = "print <string>";
91 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').";
92 mCommandDict[info.keyword] = info;
94 info.keyword = "exec";
98 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
99 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.";
100 mCommandDict[info.keyword] = info;
102 info.keyword = "package";
105 info.code = cPackage;
106 info.syntax = "package <name>";
107 info.help = "Begins the definition of a package.";
108 mCommandDict[info.keyword] = info;
110 info.keyword = "endpackage";
113 info.code = cEndPackage;
114 info.syntax = "endpackage";
115 info.help = "Ends the definition of a package.";
116 mCommandDict[info.keyword] = info;
118 info.keyword = "define";
122 info.syntax = "define <type> [<package>]";
123 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.";
124 mCommandDict[info.keyword] = info;
126 info.keyword = "endefine";
129 info.code = cEndDefine;
130 info.syntax = "endefine";
131 info.help = "Ends the definition of a new type of complex black box";
132 mCommandDict[info.keyword] = info;
134 info.keyword = "input";
138 info.syntax = "input <name> <box.input> <help>";
139 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";
140 mCommandDict[info.keyword] = info;
142 info.keyword = "output";
146 info.syntax = "output <name> <box.output> <help>";
147 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";
148 mCommandDict[info.keyword] = info;
150 info.keyword = "set";
154 info.syntax = "set <box.input> <value>";
155 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";
156 mCommandDict[info.keyword] = info;
158 info.keyword = "config"; // JPR
162 info.syntax = "config [<verbose>|<v>]";
163 info.help = "Prints the value of all configuration parameters";
164 mCommandDict[info.keyword] = info;
166 info.keyword = "index"; // LG
170 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Keywords']]";
171 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 'Keywords' is provided then the entries are either the package names or the keywords";
172 mCommandDict[info.keyword] = info;
174 info.keyword = "reset"; //EED
178 info.syntax = "reset";
179 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
180 mCommandDict[info.keyword] = info;
182 info.keyword = "author";
186 info.syntax = "author <string>";
187 info.help = "Adds the string <string> to the author information of the black box being defined";
188 mCommandDict[info.keyword] = info;
190 info.keyword = "keyword"; //JP
193 info.code = cKeyword;
194 info.syntax = "keyword <list of items, separated by ;>";
195 info.help = "Adds the string <string> to the keyword information of the black box being defined";
196 mCommandDict[info.keyword] = info;
198 info.keyword = "description";
201 info.code = cDescription;
202 info.syntax = "description <string>";
203 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
204 mCommandDict[info.keyword] = info;
206 info.keyword = "help";
210 info.syntax = "help";
211 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>";
212 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.";
213 mCommandDict[info.keyword] = info;
215 info.keyword = "message";
218 info.code = cMessage;
219 info.syntax = "message <category> <level>";
220 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.";
221 mCommandDict[info.keyword] = info;
223 info.keyword = "include";
226 info.code = cInclude;
227 info.syntax = "include <filename>";
228 info.help = "Includes the file <filename>";
229 mCommandDict[info.keyword] = info;
231 info.keyword = "quit";
235 info.syntax = "quit";
236 info.help = "Quits the program (during script execution it stops the complete execution)";
237 mCommandDict[info.keyword] = info;
239 info.keyword = "load";
243 info.syntax = "load <packagename>";
244 info.help = "Loads the black box package <packagename>";
245 mCommandDict[info.keyword] = info;
247 info.keyword = "unload";
251 info.syntax = "unload <packagename>";
252 info.help = "Unloads the black box package <packagename>";
253 mCommandDict[info.keyword] = info;
255 info.keyword = "graph";
259 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 ]]]]]]";
260 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')";
261 mCommandDict[info.keyword] = info;
264 info.keyword = "workspace";
267 info.code = cWorkspace;
268 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
269 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.";
270 mCommandDict[info.keyword] = info;
273 bbtkDebugDecTab("Interpreter",9);
276 //=======================================================================
280 //=======================================================================
284 Interpreter::~Interpreter()
286 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
290 // std::cout <<"EO Interpreter::~Interpreter()"<<std::endl;
291 bbtkDebugDecTab("Interpreter",9);
293 //=======================================================================
296 //=======================================================================
300 void Interpreter::InterpretFile( const std::string& filename, bool use_configuration_file, bool verbose)
302 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
304 bool exm = mCommandLine;
305 mCommandLine = false;
309 SwitchToFile(filename, use_configuration_file, verbose);
310 bool insideComment = false; // for multiline comment
311 while (mFile.size()>0)
313 while ((mFile.size()>0) &&
314 (!mFile.back()->eof()))
318 mFile.back()->getline(buf,500);
320 std::string str(buf);
321 int size=str.length();
322 if ( str[ size-1 ]==13 )
327 InterpretLine(str, insideComment);
329 //if (mFile.size()>0)
333 catch (QuitException e)
336 catch (bbtk::Exception e)
338 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
339 if (mFileName.size()) {
340 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
341 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
344 catch (std::exception& e)
346 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
347 if (mFileName.size()) {
348 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
349 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
354 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
355 if (mFileName.size()) {
356 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
357 std::cout << "* LINE : "<<mLine.back()<<std::endl;
362 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
363 bbtkDecTab("Interpreter",9);
367 //=======================================================================
371 //=======================================================================
375 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
378 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
379 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
381 std::vector<std::string> words;
382 SplitLine(line,words);
387 bbtkDebugDecTab("Interpreter",9);
391 // Single line comment : # or //
392 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
394 bbtkDebugDecTab("Interpreter",9);
395 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
399 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
401 if (words[0][0]=='/' && words[0][1]=='*')
403 bbtkDebugDecTab("Interpreter",9);
404 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
405 insideComment = true;
409 if (words[0][0]=='*' && words[0][1]=='/')
411 bbtkDebugDecTab("Interpreter",9);
412 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
413 if ( !insideComment ) {
414 bbtkDebugDecTab("Interpreter",9);
415 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
417 insideComment = false;
423 bbtkDebugDecTab("Interpreter",9);
424 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
429 CommandInfoType command;
430 InterpretCommand(words,command);
432 bbtkDebugMessage("Interpreter",9,
433 "Command='"<<command.keyword
434 <<"' code="<<command.code<<std::endl);
436 std::string left,right,left2,right2;
437 std::string filename;
438 switch (command.code)
441 mExecuter->Create(words[1],words[2]);
446 // mExecuter->Remove(words[1]);
450 Utilities::SplitAroundFirstDot(words[1],left,right);
451 Utilities::SplitAroundFirstDot(words[2],left2,right2);
452 mExecuter->Connect(left,right,left2,right2);
456 mExecuter->BeginPackage(words[1]);
460 mExecuter->EndPackage();
464 if (mFileName.size()>0)
466 filename = Utilities::get_file_name(mFileName.back());
470 mExecuter->Define(words[1],"",filename);
474 mExecuter->Define(words[1],words[2],filename);
479 mExecuter->EndDefine();
483 Print(words[1]); /// \todo use mExecuter
487 if (words[1]=="freeze")
488 mExecuter->SetNoExecMode(true);
489 else if (words[1]=="unfreeze")
490 mExecuter->SetNoExecMode(false);
492 mExecuter->Update(words[1]);
496 Utilities::SplitAroundFirstDot(words[2],left,right);
497 mExecuter->DefineInput(words[1],left,right,words[3]);
501 Utilities::SplitAroundFirstDot(words[2],left,right);
502 mExecuter->DefineOutput(words[1],left,right,words[3]);
506 Utilities::SplitAroundFirstDot(words[1],left,right);
507 mExecuter->Set(left,right,words[2]);
511 mExecuter->Author(words[1]);
515 mExecuter->Keyword(words[1]);
520 Index("tmp_index.html");
521 else if (words.size()==2)
523 else if (words.size()==3)
524 Index(words[1],words[2]);
527 mExecuter->Description(words[1]);
537 bbtk::MessageManager::PrintInfo();
541 sscanf(words[2].c_str(),"%d",&level);
542 bbtk::MessageManager::SetMessageLevel(words[1],level);
551 if (words.size()>1) // any param for config means verbose = true
559 this->mExecuter->Reset();
565 InterpretFile(words[1], true, verbose); // true : better pass use_config_file
569 SwitchToFile(words[1], true, verbose); // true : better pass use_config_file
574 LoadPackage(words[1], true, verbose); // true : better pass use_config_file
578 UnLoadPackage(words[1]);
582 throw QuitException();
586 if (words.size() == 2)
588 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
589 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
593 mExecuter->SetWorkspaceName(words[2]);
598 bbtkInternalError("should not reach here !!!");
601 bbtkDecTab("Interpreter",9);
603 //=======================================================================
609 //=======================================================================
613 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
615 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
617 std::string delimiters = "\"";
618 std::vector<std::string> quote;
619 Utilities::SplitString(str,delimiters,quote);
622 std::vector<std::string>::iterator i;
623 for (i=quote.begin(); i!=quote.end(); )
625 Utilities::SplitString(*i,delimiters,tokens);
629 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
630 tokens.push_back(*i);
635 for (i=tokens.begin(); i!=tokens.end(); ++i)
637 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
639 bbtkDebugMessageCont("Interpreter",9,std::endl);
641 bbtkDebugDecTab("Interpreter",9);
643 //=======================================================================
646 //=======================================================================
647 // Replaces substrings "\\n" by a real carriage return "\n"
648 void SubsBackslashN ( std::string& s )
650 // std::cout << "BEFORE=["<<s<<"]"<<std::endl;
651 std::string ss("\\n");
652 std::string::size_type pos = 0;
655 while ( pos != std::string::npos )
657 // std::cout << "*** find one "<<std::endl;
658 s.replace(pos,2,cr,1);
659 pos = s.find(ss, pos-1);
661 // std::cout << "AFTER=["<<s<<"]"<<std::endl;
663 //=======================================================================
666 //=======================================================================
670 void Interpreter::Print( const std::string& str)
672 if (mExecuter->GetNoExecMode()) return;
674 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
676 std::vector<std::string> chains;
677 std::string delimiters("$");
679 // Skip delimiters at beginning.
680 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
682 if (lastPos>0) is_text = false;
684 // Find first delimiter.
685 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
687 while (std::string::npos != pos || std::string::npos != lastPos)
691 // Found a text token, add it to the vector.
692 chains.push_back(str.substr(lastPos, pos - lastPos));
693 // std::cout << "text='"<<chains.back()<<"'"<<std::endl;
697 // is an output (between $$) : decode
698 std::string tok,box,output;
699 tok = str.substr(lastPos, pos - lastPos);
700 Utilities::SplitAroundFirstDot(tok,box,output);
701 chains.push_back( mExecuter->Get(box,output) );
702 // std::cout << "outp='"<<chains.back()<<"'"<<std::endl;
704 // Skip delimiters. Note the "not_of"
705 lastPos = str.find_first_not_of(delimiters, pos);
706 // Find next delimiter
707 pos = str.find_first_of(delimiters, lastPos);
711 // std::cout << "nb="<<chains.size()<<std::endl;
712 std::vector<std::string>::iterator i;
713 for (i= chains.begin(); i!=chains.end(); ++i)
715 // bbtkMessage("Echo",1,*i);
719 std::cout << std::endl;
720 bbtkDebugDecTab("Interpreter",9);
723 //=======================================================================
728 // ===================================================================================
730 void Interpreter::SwitchToFile( const std::string& name,
731 bool use_configuration_file, bool verbose)
733 // Note : in the following :
734 // name : the user supplied name
735 // - abreviated name e.g. scr scr.bbs
736 // - relative full name e.g. ./scr.bbs ../../scr.bbs
737 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
738 // same for Windows, with c:, d: ...
740 // use ./directory/subdir/scrname.bbs
743 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
744 <<name<<"\")"<<std::endl);
746 // to be removed in final version
749 std::vector<std::string> script_paths;
750 std::string fullPathScriptName; // full path script name
751 std::string pkgname; // e.g. <scriptname>.bbs
752 std::vector<std::string> Filenames;
754 if (use_configuration_file)
756 // The following is *NOT* a debug time message :
757 // It's a user intended message.
758 // Please don't remove it.
760 std::cout << "look for : [" << name << "] (use_configuration_file == TRUE)" << std::endl;
761 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
764 pkgname = Utilities::ExtractScriptName(name,upath);
765 //std::cout <<"name [" << name << "] pkgname [" << pkgname << "] upath [" << upath << "]" << std::endl;
766 bool fullnameGiven = false;
767 bool foundFile = false;
769 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
773 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
775 int nbFiles = Utilities::Explore(upath, false, Filenames);
777 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
779 if ((*i).substr((*i).size()-4, 4) != ".bbs")
780 continue; // ignore non .bbs files
786 std::cout << "WARNING : No '.bbs' file found in [" << upath << "]" << std::endl;
793 std::vector<std::string>::iterator i;
794 std::string fullDirectoryName;
795 for (i=script_paths.begin();i!=script_paths.end();++i)// ==== relative name, iterate + load all .bbs files
799 // we *really* want '.' to be the current working directory
801 char buf[2048]; // for getcwd
802 char * currentDir = getcwd(buf, 2048);
803 std::string cwd(currentDir);
807 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
808 //std::cout <<"fullpath [" << fullDirectoryName << "]" <<std::endl;
809 // std::cout << "== "<<fullDirectoryName<<" =="<<std::endl;
812 // Check if library exists
813 if ( ! Utilities::IsDirectory(fullDirectoryName) )
815 // The following is *NOT* a debug time message :
816 // It's a user intended message.
817 // Please don't remove it.
819 std::cout <<" [" <<fullDirectoryName <<"] : doesn't exist" <<std::endl;
820 continue; // try next path
825 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
826 // std::cout << "=================nbFiles " << nbFiles << std::endl;
828 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
830 // std::cout << "=== "<<*i<<" =="<<std::endl;
831 if ((*i).substr((*i).size()-4, 4) != ".bbs")
832 continue; // ignore non .bbs files
838 std::cout << "WARNING : No '.bbs' file found in [" << fullDirectoryName << "]" << std::endl;
840 //break; // a directory was found; we stop iterating
841 // LG : No! We want all files included !
846 //std::string::size_type slash_position = name.find_last_of("/\\");
848 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
849 // (not only a plain script name)
850 // we trust him, and try to expland the directory name
851 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
853 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
856 // ===========================================================check user supplied location
857 fullnameGiven = true;
859 fullPathScriptName = Utilities::ExpandLibName(name, verbose);
861 // allow user to always forget ".bbs"
862 int l = fullPathScriptName.size();
868 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
870 fullPathScriptName = fullPathScriptName + ".bbs";
875 fullPathScriptName = fullPathScriptName + ".bbs";
878 if ( Utilities::FileExists(fullPathScriptName))
886 // =============================================================== iterate on the paths
889 std::vector<std::string>::iterator i;
890 for (i=script_paths.begin();i!=script_paths.end();++i)
894 // we *really* want '.' to be the current working directory
896 char buf[2048]; // for getcwd
897 char * currentDir = getcwd(buf, 2048);
898 std::string cwd(currentDir);
902 // fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true); //pkgname);
904 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
905 //std::cout << "FULL PATH = "<<fullPathScriptName<<std::endl;
907 // Check if library exists
908 if ( ! Utilities::FileExists(fullPathScriptName) )
910 // The following is *NOT* a debug time message :
911 // It's a user intended message.
912 // Please don't remove it.
914 std::cout <<" [" <<fullPathScriptName <<"] : doesn't exist" <<std::endl;
915 continue; // try next path
918 std::cout <<" [" <<fullPathScriptName <<"] : found" <<std::endl;
920 break; // a script was found; we stop iterating
922 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
928 if(fullPathScriptName == "")
929 bbtkError("Path ["<<upath<<"] doesn't exist");
931 bbtkError("Script ["<<fullPathScriptName<<"] not found");
933 bbtkError("No ["<<pkgname<<".bbs] script found");
937 LoadScript(fullPathScriptName);
943 //=======================================================================
945 void Interpreter::LoadScript( std::string fullPathScriptName)
947 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)
950 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName<<"' already open : do not open it once more to prevent recursive inclusion"<<std::endl);
954 bbtkMessage("Interpreter",1,fullPathScriptName<<" found"<<std::endl);
957 s = new std::ifstream;
958 s->open(fullPathScriptName.c_str());
961 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
966 std::cout << " -->[" << fullPathScriptName << "] found" << std::endl;
969 mFileName.push_back(fullPathScriptName);
974 //=======================================================================
978 void Interpreter::CloseCurrentFile()
980 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
985 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
989 mFile.back()->close();
992 bbtkDebugMessage("Interpreter",9,
993 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
995 mFileName.pop_back();
997 bbtkDebugMessage("Interpreter",9," Remains "
999 <<" open"<<std::endl);
1000 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1003 //=======================================================================
1005 //=======================================================================
1009 void Interpreter::CloseAllFiles()
1011 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1014 while (mFile.size() != 0)
1016 mFile.back()->close();
1017 delete mFile.back();
1019 bbtkDebugMessage("Interpreter",9,
1020 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1021 mFileName.pop_back();
1024 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1027 //=======================================================================
1031 //=======================================================================
1035 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1036 CommandInfoType& info )
1038 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1040 // searches the command keyword
1041 CommandDictType::iterator c;
1042 c = mCommandDict.find(words[0]);
1043 if ( c == mCommandDict.end() ) {
1044 bbtkError(words[0]<<" : unknown command");
1047 // tests the number of args
1048 if ( ( words.size()-1 < c->second.argmin ) ||
1049 ( words.size()-1 > c->second.argmax ) )
1051 HelpCommand(words[0]);
1052 bbtkError(words[0]<<" : wrong number of arguments");
1056 bbtkDecTab("Interpreter",9);
1058 //=======================================================================
1061 //=======================================================================
1062 /// Displays help on all the commands
1063 void Interpreter::Help(const std::vector<std::string>& words)
1065 unsigned int nbarg = words.size()-1;
1073 if (words[1]=="packages")
1075 PrintPackages(true);
1080 HelpCommand(words[1]);
1082 catch (bbtk::Exception e)
1086 HelpPackage(words[1]);
1088 catch (bbtk::Exception f)
1092 HelpBlackBox(words[1]);
1094 catch (bbtk::Exception g)
1098 this->mExecuter->ShowRelations(words[1],"0","9999");
1100 catch (bbtk::Exception h){
1101 bbtkError("\""<<words[1].c_str()
1102 <<"\" is not a known command, package, black box type or black box name");
1110 if (words[2]=="all")
1112 if ( words[1]=="packages" )
1114 PrintPackages(true,true);
1119 HelpPackage(words[1],true);
1121 catch (bbtk::Exception f)
1127 HelpCommand(words[0]);
1128 bbtkError(words[0]<<" : syntax error");
1133 bbtkError("Should not reach here !!!");
1136 //=======================================================================
1138 //===================================================================
1139 /// Displays the Configuration
1140 void Interpreter::Config( bool verbose ) const
1142 bbtkDebugMessageInc("Core",9,"Factory::Config"<<std::endl);
1144 ConfigurationFile cf = ConfigurationFile::GetInstance();
1146 const std::string config_xml_full_path = cf.Get_config_xml_full_path();
1147 const std::string description = cf.Get_description();
1148 const std::string url = cf.Get_url();
1149 const std::string data_path = cf.Get_data_path();
1150 const std::string default_doc_tmp = cf.Get_default_doc_tmp();
1151 const std::string file_separator = cf.Get_file_separator();
1152 const std::vector<std::string>bbs_paths = cf.Get_bbs_paths();
1153 const std::vector<std::string>package_paths = cf.Get_package_paths();
1155 bbtkMessage("Help",1, "=============" << std::endl);
1156 bbtkMessage("Help",1, "Configuration" << std::endl);
1157 bbtkMessage("Help",1, "=============" << std::endl);
1158 bbtkMessage("Help",1, "bbtk_config.xml : [" << config_xml_full_path << "]" << std::endl);
1159 bbtkMessage("Help",1, "Documentation Url : [" << url << "]" << std::endl);
1160 bbtkMessage("Help",1, "Data Path : [" << data_path << "]" << std::endl);
1161 bbtkMessage("Help",1, "Default Doc_tmp : [" << default_doc_tmp << "]" << std::endl);
1162 bbtkMessage("Help",1, "File Separator : [" << file_separator << "]" << std::endl);
1164 std::vector<std::string>::const_iterator i;
1166 bbtkMessage("Help",1, "BBS Paths " << std::endl);
1167 for (i = bbs_paths.begin(); i!=bbs_paths.end(); ++i )
1169 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1172 bbtkMessage("Help",1, "PACKAGE Paths : " << std::endl);
1173 for (i = package_paths.begin(); i!=package_paths.end(); ++i )
1175 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1178 bbtkDebugDecTab("Core",9);
1181 //=======================================================================
1182 /// Displays help on all the commands
1183 void Interpreter::HelpCommands()
1185 std::cout << "Available commands :" << std::endl;
1186 CommandDictType::iterator i;
1187 for ( i = mCommandDict.begin();
1188 i != mCommandDict.end();
1190 std::cout << " " << i->first << std::endl;
1191 // std::cout << " usage : " << i->second.syntax << std::endl;
1192 // std::cout << " " << i->second.help << std::endl;
1196 //=======================================================================
1199 //=======================================================================
1200 /// Displays help on a particular commands
1201 void Interpreter::HelpCommand(const std::string& s)
1203 CommandDictType::iterator c;
1204 c = mCommandDict.find(s);
1205 if ( c == mCommandDict.end() ) {
1206 bbtkError(s<<" : Unknown command");
1208 // std::cout << " " << s << " : "<< std::endl;
1209 // CommandParamDictType::iterator i;
1210 // for ( i = c->second.begin();
1211 // i != c->second.end();
1213 std::cout << " usage : " << c->second.syntax << std::endl;
1214 std::cout << " " << c->second.help << std::endl;
1217 //=======================================================================
1220 //=======================================================================
1221 /// Fills the vector commands with the commands which
1222 /// have the first n chars of buf for prefix
1223 /// TODO : skip initial spaces in buf and also return the position of first
1224 /// non blank char in buf
1225 void Interpreter::FindCommandsWithPrefix( char* buf,
1227 std::vector<std::string>& commands )
1229 CommandDictType::const_iterator i;
1230 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1232 if ((i->first).find(buf,0,n) == 0)
1233 commands.push_back(i->first);
1236 //=======================================================================
1240 //=======================================================================
1241 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1243 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1244 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1246 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1247 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1248 // E.G. STORE THIS IN bbtk_config.xml
1249 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1250 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1251 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1252 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1253 #define BBTK_BACKSPACE_KBCODE 0x00000008
1254 #define BBTK_DEL_KBCODE 0x0000007F
1255 #define BBTK_SPACE_KBCODE 0x00000020
1257 //=======================================================================
1258 void Interpreter::GetLineFromPrompt(std::string& s)
1263 int MAX_LINE_SIZE = 160;
1264 int MAX_HISTORY_SIZE = 100;
1266 char* newline = new char[MAX_LINE_SIZE];
1267 memset(newline,0,MAX_LINE_SIZE);
1268 char* histline = new char[MAX_LINE_SIZE];
1269 memset(histline,0,MAX_LINE_SIZE);
1271 char* line = newline;
1272 int hist = mHistory.size();
1279 read ( STDIN_FILENO, &c, 4) ;
1281 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1283 // Printable character
1284 if ( (ind<MAX_LINE_SIZE-1) &&
1285 ( c >= BBTK_SPACE_KBCODE ) &&
1286 ( c < BBTK_DEL_KBCODE ))
1294 // delete the unused line
1300 // empty lines are not stored in from history
1303 // if history too long : delete oldest command
1304 if (mHistory.size()>MAX_HISTORY_SIZE)
1306 delete mHistory.front();
1307 mHistory.pop_front();
1309 mHistory.push_back(line);
1314 else if ( (ind>0) &&
1315 ((c == BBTK_BACKSPACE_KBCODE) ||
1316 (c == BBTK_DEL_KBCODE)) )
1324 // TODO : Command completion
1325 std::vector<std::string> commands;
1326 FindCommandsWithPrefix( line,ind,commands);
1327 if (commands.size()==1)
1329 std::string com = *commands.begin();
1330 for (; ind<com.size(); ++ind)
1332 PrintChar(com[ind]);
1338 else if (commands.size()>1)
1340 std::vector<std::string>::iterator i;
1342 for (i=commands.begin();i!=commands.end();++i)
1344 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1347 write(STDOUT_FILENO,"\n> ",3);
1348 //for (int j=0;j<ind;++j)
1350 write(STDOUT_FILENO,line,ind);
1354 // Arrow up : back in history
1355 else if (c==BBTK_UP_ARROW_KBCODE)
1359 // erase current line
1360 while (ind--) BackSpace();
1364 strcpy(histline,mHistory[hist]);
1368 write(STDOUT_FILENO,line,ind);
1371 // Arrow down : down in history
1372 else if (c==BBTK_DOWN_ARROW_KBCODE)
1374 if (hist<mHistory.size()-1)
1376 // erase current line
1377 while (ind--) BackSpace();
1381 strcpy(histline,mHistory[hist]);
1385 write(STDOUT_FILENO,line,ind);
1387 // end of history : switch back to newline
1388 else if (hist==mHistory.size()-1)
1390 // erase current line
1391 while (ind--) BackSpace();
1398 write(STDOUT_FILENO,line,ind);
1402 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1404 PrintChar(line[ind]);
1409 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1417 write(STDOUT_FILENO,"\n\r",2);
1425 //=======================================================================
1426 void Interpreter::GetLineFromPrompt(std::string& s)
1452 //=======================================================================
1458 //=======================================================================
1459 void Interpreter::CommandLineInterpreter()
1461 bbtkDebugMessageInc("Interpreter",9,
1462 "Interpreter::CommandLineInterpreter()"<<std::endl);
1464 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1465 // Initialise the tty in non canonical mode with no echo
1466 // oter remembers the previous settings to restore them after
1467 struct termios ter,oter;
1470 ter.c_lflag &= ~ECHO;
1471 ter.c_lflag &= ~ICANON;
1474 tcsetattr(0,TCSANOW,&ter);
1477 mCommandLine = true;
1479 bool insideComment = false; // for multiline comment
1485 GetLineFromPrompt(line);
1486 InterpretLine(line, insideComment);
1488 catch (QuitException e)
1492 catch (bbtk::Exception e)
1496 catch (std::exception& e)
1498 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1502 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1507 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1508 tcsetattr(0,TCSANOW,&oter);
1511 std::cout << "Good bye !" << std::endl;
1513 bbtkDebugDecTab("Interpreter",9);
1516 //=======================================================================
1517 void Interpreter::Graph(const std::vector<std::string>& words)
1520 bool system_display = true;
1522 #ifdef _USE_WXWIDGETS_
1523 if ( WxConsole::GetInstance() != 0 ) system_display = false;
1526 if (words.size()==1)
1528 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1530 else if (words.size()==2)
1532 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1534 else if (words.size()==3)
1536 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1538 else if (words.size()==4)
1540 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1542 else if (words.size()==5)
1544 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1546 else if (words.size()==6)
1548 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1550 else if (words.size()==7)
1552 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1555 #ifdef _USE_WXWIDGETS_
1556 if ( WxConsole::GetInstance() != 0 )
1557 WxConsole::GetInstance()->ShowHtmlPage(page);
1560 //=======================================================================
1563 //=======================================================================
1564 void Interpreter::Index(const std::string& filename,
1565 const std::string& type)
1567 Factory::IndexEntryType t;
1568 if (type=="Initials") t = Factory::Initials;
1569 else if (type=="Keywords") t = Factory::Keywords;
1570 else if (type=="Packages") t = Factory::Packages;
1572 GetGlobalFactory()->CreateHtmlIndex(t,filename);
1574 //=======================================================================