1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/02/12 12:55:16 $
7 Version: $Revision: 1.29 $
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]);
1086 #ifdef _USE_WXWIDGETS_
1087 if ( WxConsole::GetInstance() != 0 )
1089 std::string url = ConfigurationFile::GetInstance().Get_url();
1090 url += "/bbdoc/" + words[1] + "/index.html";
1091 if (Utilities::FileExists(url))
1093 WxConsole::GetInstance()->ShowHtmlPage(url);
1098 catch (bbtk::Exception f)
1102 std::string package;
1103 HelpBlackBox(words[1],package);
1104 #ifdef _USE_WXWIDGETS_
1105 if ( WxConsole::GetInstance() != 0 )
1107 std::string url = ConfigurationFile::GetInstance().Get_url();
1108 url += "/bbdoc/" + package + "/index.html";
1109 if (Utilities::FileExists(url))
1111 url += "#" + words[1];
1112 WxConsole::GetInstance()->ShowHtmlPage(url);
1117 catch (bbtk::Exception g)
1121 this->mExecuter->ShowRelations(words[1],"0","9999");
1123 catch (bbtk::Exception h){
1124 bbtkError("\""<<words[1].c_str()
1125 <<"\" is not a known command, package, black box type or black box name");
1133 if (words[2]=="all")
1135 if ( words[1]=="packages" )
1137 PrintPackages(true,true);
1142 HelpPackage(words[1],true);
1144 catch (bbtk::Exception f)
1150 HelpCommand(words[0]);
1151 bbtkError(words[0]<<" : syntax error");
1156 bbtkError("Should not reach here !!!");
1159 //=======================================================================
1161 //===================================================================
1162 /// Displays the Configuration
1163 void Interpreter::Config() const
1165 bbtkDebugMessageInc("Kernel",9,"Factory::Config"<<std::endl);
1167 ConfigurationFile cf = ConfigurationFile::GetInstance();
1169 const std::string config_xml_full_path = cf.Get_config_xml_full_path();
1170 const std::string description = cf.Get_description();
1171 const std::string url = cf.Get_url();
1172 const std::string data_path = cf.Get_data_path();
1173 const std::string default_temp_dir = cf.Get_default_temp_dir();
1174 const std::string file_separator = cf.Get_file_separator();
1175 const std::vector<std::string>bbs_paths = cf.Get_bbs_paths();
1176 const std::vector<std::string>package_paths = cf.Get_package_paths();
1178 bbtkMessage("Help",1, "=============" << std::endl);
1179 bbtkMessage("Help",1, "Configuration" << std::endl);
1180 bbtkMessage("Help",1, "=============" << std::endl);
1181 bbtkMessage("Help",1, "bbtk_config.xml : [" << config_xml_full_path << "]" << std::endl);
1182 bbtkMessage("Help",1, "Documentation Url : [" << url << "]" << std::endl);
1183 bbtkMessage("Help",1, "Data Path : [" << data_path << "]" << std::endl);
1184 bbtkMessage("Help",1, "Default Temp-Dir : [" << default_temp_dir << "]" << std::endl);
1185 bbtkMessage("Help",1, "File Separator : [" << file_separator << "]" << std::endl);
1187 std::vector<std::string>::const_iterator i;
1189 bbtkMessage("Help",1, "BBS Paths " << std::endl);
1190 for (i = bbs_paths.begin(); i!=bbs_paths.end(); ++i )
1192 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1195 bbtkMessage("Help",1, "PACKAGE Paths : " << std::endl);
1196 for (i = package_paths.begin(); i!=package_paths.end(); ++i )
1198 bbtkMessage("Help",1,"--- ["<<*i<<"]"<<std::endl);
1201 bbtkDebugDecTab("Kernel",9);
1204 //=======================================================================
1205 /// Displays help on all the commands
1206 void Interpreter::HelpCommands()
1208 std::cout << "Available commands :" << std::endl;
1209 CommandDictType::iterator i;
1210 for ( i = mCommandDict.begin();
1211 i != mCommandDict.end();
1213 std::cout << " " << i->first << std::endl;
1214 // std::cout << " usage : " << i->second.syntax << std::endl;
1215 // std::cout << " " << i->second.help << std::endl;
1219 //=======================================================================
1222 //=======================================================================
1223 /// Displays help on a particular commands
1224 void Interpreter::HelpCommand(const std::string& s)
1226 CommandDictType::iterator c;
1227 c = mCommandDict.find(s);
1228 if ( c == mCommandDict.end() ) {
1229 bbtkError(s<<" : Unknown command");
1231 // std::cout << " " << s << " : "<< std::endl;
1232 // CommandParamDictType::iterator i;
1233 // for ( i = c->second.begin();
1234 // i != c->second.end();
1236 std::cout << " usage : " << c->second.syntax << std::endl;
1237 std::cout << " " << c->second.help << std::endl;
1240 //=======================================================================
1243 //=======================================================================
1244 /// Fills the vector commands with the commands which
1245 /// have the first n chars of buf for prefix
1246 /// TODO : skip initial spaces in buf and also return the position of first
1247 /// non blank char in buf
1248 void Interpreter::FindCommandsWithPrefix( char* buf,
1250 std::vector<std::string>& commands )
1252 CommandDictType::const_iterator i;
1253 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1255 if ((i->first).find(buf,0,n) == 0)
1256 commands.push_back(i->first);
1259 //=======================================================================
1263 //=======================================================================
1264 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1266 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1267 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1269 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1270 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1271 // E.G. STORE THIS IN bbtk_config.xml
1272 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1273 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1274 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1275 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1276 #define BBTK_BACKSPACE_KBCODE 0x00000008
1277 #define BBTK_DEL_KBCODE 0x0000007F
1278 #define BBTK_SPACE_KBCODE 0x00000020
1280 //=======================================================================
1281 void Interpreter::GetLineFromPrompt(std::string& s)
1286 int MAX_LINE_SIZE = 160;
1287 int MAX_HISTORY_SIZE = 100;
1289 char* newline = new char[MAX_LINE_SIZE];
1290 memset(newline,0,MAX_LINE_SIZE);
1291 char* histline = new char[MAX_LINE_SIZE];
1292 memset(histline,0,MAX_LINE_SIZE);
1294 char* line = newline;
1295 int hist = mHistory.size();
1302 read ( STDIN_FILENO, &c, 4) ;
1304 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1306 // Printable character
1307 if ( (ind<MAX_LINE_SIZE-1) &&
1308 ( c >= BBTK_SPACE_KBCODE ) &&
1309 ( c < BBTK_DEL_KBCODE ))
1317 // delete the unused line
1323 // empty lines are not stored in from history
1326 // if history too long : delete oldest command
1327 if (mHistory.size()>MAX_HISTORY_SIZE)
1329 delete mHistory.front();
1330 mHistory.pop_front();
1332 mHistory.push_back(line);
1337 else if ( (ind>0) &&
1338 ((c == BBTK_BACKSPACE_KBCODE) ||
1339 (c == BBTK_DEL_KBCODE)) )
1347 // TODO : Command completion
1348 std::vector<std::string> commands;
1349 FindCommandsWithPrefix( line,ind,commands);
1350 if (commands.size()==1)
1352 std::string com = *commands.begin();
1353 for (; ind<com.size(); ++ind)
1355 PrintChar(com[ind]);
1361 else if (commands.size()>1)
1363 std::vector<std::string>::iterator i;
1365 for (i=commands.begin();i!=commands.end();++i)
1367 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1370 write(STDOUT_FILENO,"\n> ",3);
1371 //for (int j=0;j<ind;++j)
1373 write(STDOUT_FILENO,line,ind);
1377 // Arrow up : back in history
1378 else if (c==BBTK_UP_ARROW_KBCODE)
1382 // erase current line
1383 while (ind--) BackSpace();
1387 strcpy(histline,mHistory[hist]);
1391 write(STDOUT_FILENO,line,ind);
1394 // Arrow down : down in history
1395 else if (c==BBTK_DOWN_ARROW_KBCODE)
1397 if (hist<mHistory.size()-1)
1399 // erase current line
1400 while (ind--) BackSpace();
1404 strcpy(histline,mHistory[hist]);
1408 write(STDOUT_FILENO,line,ind);
1410 // end of history : switch back to newline
1411 else if (hist==mHistory.size()-1)
1413 // erase current line
1414 while (ind--) BackSpace();
1421 write(STDOUT_FILENO,line,ind);
1425 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1427 PrintChar(line[ind]);
1432 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1440 write(STDOUT_FILENO,"\n\r",2);
1448 //=======================================================================
1449 void Interpreter::GetLineFromPrompt(std::string& s)
1475 //=======================================================================
1481 //=======================================================================
1482 void Interpreter::CommandLineInterpreter()
1484 bbtkDebugMessageInc("Interpreter",9,
1485 "Interpreter::CommandLineInterpreter()"<<std::endl);
1487 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1488 // Initialise the tty in non canonical mode with no echo
1489 // oter remembers the previous settings to restore them after
1490 struct termios ter,oter;
1493 ter.c_lflag &= ~ECHO;
1494 ter.c_lflag &= ~ICANON;
1497 tcsetattr(0,TCSANOW,&ter);
1500 mCommandLine = true;
1502 bool insideComment = false; // for multiline comment
1508 GetLineFromPrompt(line);
1509 InterpretLine(line, insideComment);
1511 catch (QuitException e)
1515 catch (bbtk::Exception e)
1519 catch (std::exception& e)
1521 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1525 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1530 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1531 tcsetattr(0,TCSANOW,&oter);
1534 std::cout << "Good bye !" << std::endl;
1536 bbtkDebugDecTab("Interpreter",9);
1539 //=======================================================================
1540 void Interpreter::Graph(const std::vector<std::string>& words)
1543 bool system_display = true;
1545 #ifdef _USE_WXWIDGETS_
1546 if ( WxConsole::GetInstance() != 0 ) system_display = false;
1549 if (words.size()==1)
1551 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1553 else if (words.size()==2)
1555 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1557 else if (words.size()==3)
1559 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1561 else if (words.size()==4)
1563 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1565 else if (words.size()==5)
1567 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1569 else if (words.size()==6)
1571 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1573 else if (words.size()==7)
1575 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1578 #ifdef _USE_WXWIDGETS_
1579 if ( WxConsole::GetInstance() != 0 )
1580 WxConsole::GetInstance()->ShowHtmlPage(page);
1583 //=======================================================================
1586 //=======================================================================
1587 void Interpreter::Index(const std::string& filename,
1588 const std::string& type)
1590 Factory::IndexEntryType t;
1591 if (type=="Initials") t = Factory::Initials;
1592 else if (type=="Categories") t = Factory::Categories;
1593 else if (type=="Packages") t = Factory::Packages;
1595 GetGlobalFactory()->CreateHtmlIndex(t,filename);
1597 //=======================================================================