1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/02/14 10:47:51 $
7 Version: $Revision: 1.30 $
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 )
1090 ConfigurationFile::GetInstance().Get_doc_path();
1091 url += "/bbdoc/" + words[1] + "/index.html";
1092 if (Utilities::FileExists(url))
1094 WxConsole::GetInstance()->ShowHtmlPage(url);
1099 catch (bbtk::Exception f)
1103 std::string package;
1104 HelpBlackBox(words[1],package);
1105 #ifdef _USE_WXWIDGETS_
1106 if ( WxConsole::GetInstance() != 0 )
1109 ConfigurationFile::GetInstance().Get_doc_path();
1110 url += "/bbdoc/" + package + "/index.html";
1111 if (Utilities::FileExists(url))
1113 url += "#" + words[1];
1114 WxConsole::GetInstance()->ShowHtmlPage(url);
1119 catch (bbtk::Exception g)
1123 this->mExecuter->ShowRelations(words[1],"0","9999");
1125 catch (bbtk::Exception h){
1126 bbtkError("\""<<words[1].c_str()
1127 <<"\" is not a known command, package, black box type or black box name");
1135 if (words[2]=="all")
1137 if ( words[1]=="packages" )
1139 PrintPackages(true,true);
1144 HelpPackage(words[1],true);
1146 catch (bbtk::Exception f)
1152 HelpCommand(words[0]);
1153 bbtkError(words[0]<<" : syntax error");
1158 bbtkError("Should not reach here !!!");
1161 //=======================================================================
1163 //===================================================================
1164 /// Displays the Configuration
1165 void Interpreter::Config() const
1167 ConfigurationFile::GetInstance().GetHelp(1);
1169 //===================================================================
1171 //=======================================================================
1172 /// Displays help on all the commands
1173 void Interpreter::HelpCommands()
1175 std::cout << "Available commands :" << std::endl;
1176 CommandDictType::iterator i;
1177 for ( i = mCommandDict.begin();
1178 i != mCommandDict.end();
1180 std::cout << " " << i->first << std::endl;
1181 // std::cout << " usage : " << i->second.syntax << std::endl;
1182 // std::cout << " " << i->second.help << std::endl;
1186 //=======================================================================
1189 //=======================================================================
1190 /// Displays help on a particular commands
1191 void Interpreter::HelpCommand(const std::string& s)
1193 CommandDictType::iterator c;
1194 c = mCommandDict.find(s);
1195 if ( c == mCommandDict.end() ) {
1196 bbtkError(s<<" : Unknown command");
1198 // std::cout << " " << s << " : "<< std::endl;
1199 // CommandParamDictType::iterator i;
1200 // for ( i = c->second.begin();
1201 // i != c->second.end();
1203 std::cout << " usage : " << c->second.syntax << std::endl;
1204 std::cout << " " << c->second.help << std::endl;
1207 //=======================================================================
1210 //=======================================================================
1211 /// Fills the vector commands with the commands which
1212 /// have the first n chars of buf for prefix
1213 /// TODO : skip initial spaces in buf and also return the position of first
1214 /// non blank char in buf
1215 void Interpreter::FindCommandsWithPrefix( char* buf,
1217 std::vector<std::string>& commands )
1219 CommandDictType::const_iterator i;
1220 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1222 if ((i->first).find(buf,0,n) == 0)
1223 commands.push_back(i->first);
1226 //=======================================================================
1230 //=======================================================================
1231 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1233 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1234 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1236 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1237 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1238 // E.G. STORE THIS IN bbtk_config.xml
1239 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1240 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1241 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1242 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1243 #define BBTK_BACKSPACE_KBCODE 0x00000008
1244 #define BBTK_DEL_KBCODE 0x0000007F
1245 #define BBTK_SPACE_KBCODE 0x00000020
1247 //=======================================================================
1248 void Interpreter::GetLineFromPrompt(std::string& s)
1253 int MAX_LINE_SIZE = 160;
1254 int MAX_HISTORY_SIZE = 100;
1256 char* newline = new char[MAX_LINE_SIZE];
1257 memset(newline,0,MAX_LINE_SIZE);
1258 char* histline = new char[MAX_LINE_SIZE];
1259 memset(histline,0,MAX_LINE_SIZE);
1261 char* line = newline;
1262 int hist = mHistory.size();
1269 read ( STDIN_FILENO, &c, 4) ;
1271 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1273 // Printable character
1274 if ( (ind<MAX_LINE_SIZE-1) &&
1275 ( c >= BBTK_SPACE_KBCODE ) &&
1276 ( c < BBTK_DEL_KBCODE ))
1284 // delete the unused line
1290 // empty lines are not stored in from history
1293 // if history too long : delete oldest command
1294 if (mHistory.size()>MAX_HISTORY_SIZE)
1296 delete mHistory.front();
1297 mHistory.pop_front();
1299 mHistory.push_back(line);
1304 else if ( (ind>0) &&
1305 ((c == BBTK_BACKSPACE_KBCODE) ||
1306 (c == BBTK_DEL_KBCODE)) )
1314 // TODO : Command completion
1315 std::vector<std::string> commands;
1316 FindCommandsWithPrefix( line,ind,commands);
1317 if (commands.size()==1)
1319 std::string com = *commands.begin();
1320 for (; ind<com.size(); ++ind)
1322 PrintChar(com[ind]);
1328 else if (commands.size()>1)
1330 std::vector<std::string>::iterator i;
1332 for (i=commands.begin();i!=commands.end();++i)
1334 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1337 write(STDOUT_FILENO,"\n> ",3);
1338 //for (int j=0;j<ind;++j)
1340 write(STDOUT_FILENO,line,ind);
1344 // Arrow up : back in history
1345 else if (c==BBTK_UP_ARROW_KBCODE)
1349 // erase current line
1350 while (ind--) BackSpace();
1354 strcpy(histline,mHistory[hist]);
1358 write(STDOUT_FILENO,line,ind);
1361 // Arrow down : down in history
1362 else if (c==BBTK_DOWN_ARROW_KBCODE)
1364 if (hist<mHistory.size()-1)
1366 // erase current line
1367 while (ind--) BackSpace();
1371 strcpy(histline,mHistory[hist]);
1375 write(STDOUT_FILENO,line,ind);
1377 // end of history : switch back to newline
1378 else if (hist==mHistory.size()-1)
1380 // erase current line
1381 while (ind--) BackSpace();
1388 write(STDOUT_FILENO,line,ind);
1392 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1394 PrintChar(line[ind]);
1399 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1407 write(STDOUT_FILENO,"\n\r",2);
1415 //=======================================================================
1416 void Interpreter::GetLineFromPrompt(std::string& s)
1442 //=======================================================================
1448 //=======================================================================
1449 void Interpreter::CommandLineInterpreter()
1451 bbtkDebugMessageInc("Interpreter",9,
1452 "Interpreter::CommandLineInterpreter()"<<std::endl);
1454 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1455 // Initialise the tty in non canonical mode with no echo
1456 // oter remembers the previous settings to restore them after
1457 struct termios ter,oter;
1460 ter.c_lflag &= ~ECHO;
1461 ter.c_lflag &= ~ICANON;
1464 tcsetattr(0,TCSANOW,&ter);
1467 mCommandLine = true;
1469 bool insideComment = false; // for multiline comment
1475 GetLineFromPrompt(line);
1476 InterpretLine(line, insideComment);
1478 catch (QuitException e)
1482 catch (bbtk::Exception e)
1486 catch (std::exception& e)
1488 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1492 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1497 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1498 tcsetattr(0,TCSANOW,&oter);
1501 std::cout << "Good bye !" << std::endl;
1503 bbtkDebugDecTab("Interpreter",9);
1506 //=======================================================================
1507 void Interpreter::Graph(const std::vector<std::string>& words)
1510 bool system_display = true;
1512 #ifdef _USE_WXWIDGETS_
1513 if ( WxConsole::GetInstance() != 0 ) system_display = false;
1516 if (words.size()==1)
1518 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1520 else if (words.size()==2)
1522 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1524 else if (words.size()==3)
1526 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1528 else if (words.size()==4)
1530 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1532 else if (words.size()==5)
1534 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1536 else if (words.size()==6)
1538 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1540 else if (words.size()==7)
1542 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1545 #ifdef _USE_WXWIDGETS_
1546 if ( WxConsole::GetInstance() != 0 )
1547 WxConsole::GetInstance()->ShowHtmlPage(page);
1550 //=======================================================================
1553 //=======================================================================
1554 void Interpreter::Index(const std::string& filename,
1555 const std::string& type)
1557 Factory::IndexEntryType t;
1558 if (type=="Initials") t = Factory::Initials;
1559 else if (type=="Categories") t = Factory::Categories;
1560 else if (type=="Packages") t = Factory::Packages;
1562 GetGlobalFactory()->CreateHtmlIndex(t,filename);
1564 //=======================================================================