1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/02/14 20:26:54 $
7 Version: $Revision: 1.32 $
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 mExecuter = new bbtk::Executer();
57 // For the time being, comment out previous line, and
58 // uncomment next line to check Transcriptor
60 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
62 // Builds the commands dict
65 info.category = "new";
69 info.syntax = "new <type> <name>";
70 info.help = "Creates a new black box of type <type> with name <name>";
71 mCommandDict[info.category] = info;
73 info.category = "delete";
77 info.syntax = "delete <box>";
78 info.help = "Deletes the black box of name <box>";
79 mCommandDict[info.category] = info;
81 info.category = "connect";
85 info.syntax = "connect <box1.output> <box2.input>";
86 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
87 mCommandDict[info.category] = info;
89 info.category = "print";
93 info.syntax = "print <string>";
94 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').";
95 mCommandDict[info.category] = info;
97 info.category = "exec";
101 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
102 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.";
103 mCommandDict[info.category] = info;
105 info.category = "package";
108 info.code = cPackage;
109 info.syntax = "package <name>";
110 info.help = "Begins the definition of a package.";
111 mCommandDict[info.category] = info;
113 info.category = "endpackage";
116 info.code = cEndPackage;
117 info.syntax = "endpackage";
118 info.help = "Ends the definition of a package.";
119 mCommandDict[info.category] = info;
121 info.category = "define";
125 info.syntax = "define <type> [<package>]";
126 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.";
127 mCommandDict[info.category] = info;
129 info.category = "endefine";
132 info.code = cEndDefine;
133 info.syntax = "endefine";
134 info.help = "Ends the definition of a new type of complex black box";
135 mCommandDict[info.category] = info;
137 info.category = "input";
141 info.syntax = "input <name> <box.input> <help>";
142 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";
143 mCommandDict[info.category] = info;
145 info.category = "output";
149 info.syntax = "output <name> <box.output> <help>";
150 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";
151 mCommandDict[info.category] = info;
153 info.category = "set";
157 info.syntax = "set <box.input> <value>";
158 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";
159 mCommandDict[info.category] = info;
161 info.category = "config"; // JPR
165 info.syntax = "config";
166 info.help = "Prints the value of all configuration parameters";
167 mCommandDict[info.category] = info;
169 info.category = "index"; // LG
174 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories']]";
175 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";
176 mCommandDict[info.category] = info;
178 info.category = "reset"; //EED
182 info.syntax = "reset";
183 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
184 mCommandDict[info.category] = info;
186 info.category = "author";
190 info.syntax = "author <string>";
191 info.help = "Adds the string <string> to the author information of the black box being defined";
192 mCommandDict[info.category] = info;
194 info.category = "category"; //JP
197 info.code = cCategory;
198 info.syntax = "category <list of items, separated by ;>";
199 info.help = "Adds the string <string> to the category information of the black box being defined";
200 mCommandDict[info.category] = info;
202 info.category = "description";
205 info.code = cDescription;
206 info.syntax = "description <string>";
207 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
208 mCommandDict[info.category] = info;
210 info.category = "help";
214 info.syntax = "help";
215 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>";
216 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.";
217 mCommandDict[info.category] = info;
219 info.category = "message";
222 info.code = cMessage;
223 info.syntax = "message <kind> <level>";
224 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;
226 info.category = "include";
229 info.code = cInclude;
230 info.syntax = "include <filename> [source]";
231 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).";
232 mCommandDict[info.category] = info;
234 info.category = "quit";
238 info.syntax = "quit";
239 info.help = "Quits the program (during script execution it stops the complete execution)";
240 mCommandDict[info.category] = info;
242 info.category = "load";
246 info.syntax = "load <packagename>";
247 info.help = "Loads the black box package <packagename>";
248 mCommandDict[info.category] = info;
250 info.category = "unload";
254 info.syntax = "unload <packagename>";
255 info.help = "Unloads the black box package <packagename>";
256 mCommandDict[info.category] = info;
258 info.category = "graph";
262 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 ]]]]]]";
263 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')";
264 mCommandDict[info.category] = info;
267 info.category = "workspace";
270 info.code = cWorkspace;
271 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
272 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.";
273 mCommandDict[info.category] = info;
276 bbtkDebugDecTab("Interpreter",9);
279 //=======================================================================
283 //=======================================================================
287 Interpreter::~Interpreter()
289 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
293 bbtkDebugDecTab("Interpreter",9);
295 //=======================================================================
298 //=======================================================================
302 void Interpreter::InterpretFile( const std::string& filename,
303 bool use_configuration_file)
305 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
307 bool exm = mCommandLine;
308 mCommandLine = false;
312 SwitchToFile(filename, use_configuration_file);
313 bool insideComment = false; // for multiline comment
314 while (mFile.size()>0)
316 while ((mFile.size()>0) &&
317 (!mFile.back()->eof()))
321 mFile.back()->getline(buf,500);
323 std::string str(buf);
324 int size=str.length();
325 if ( str[ size-1 ]==13 )
330 InterpretLine(str, insideComment);
332 //if (mFile.size()>0)
336 catch (QuitException e)
339 catch (bbtk::Exception e)
341 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
342 if (mFileName.size()) {
343 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
344 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
347 catch (std::exception& e)
349 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
350 if (mFileName.size()) {
351 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
352 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
357 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
358 if (mFileName.size()) {
359 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
360 std::cout << "* LINE : "<<mLine.back()<<std::endl;
365 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
366 bbtkDecTab("Interpreter",9);
370 //=======================================================================
374 //=======================================================================
378 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
381 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
382 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
384 std::vector<std::string> words;
385 SplitLine(line,words);
390 bbtkDebugDecTab("Interpreter",9);
394 // Single line comment : # or //
395 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
397 bbtkDebugDecTab("Interpreter",9);
398 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
402 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
404 if (words[0][0]=='/' && words[0][1]=='*')
406 bbtkDebugDecTab("Interpreter",9);
407 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
408 insideComment = true;
412 if (words[0][0]=='*' && words[0][1]=='/')
414 bbtkDebugDecTab("Interpreter",9);
415 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
416 if ( !insideComment ) {
417 bbtkDebugDecTab("Interpreter",9);
418 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
420 insideComment = false;
426 bbtkDebugDecTab("Interpreter",9);
427 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
432 CommandInfoType command;
433 InterpretCommand(words,command);
435 bbtkDebugMessage("Interpreter",9,
436 "Command='"<<command.category
437 <<"' code="<<command.code<<std::endl);
439 std::string left,right,left2,right2;
440 std::string filename;
441 switch (command.code)
444 mExecuter->Create(words[1],words[2]);
449 // mExecuter->Remove(words[1]);
453 Utilities::SplitAroundFirstDot(words[1],left,right);
454 Utilities::SplitAroundFirstDot(words[2],left2,right2);
455 mExecuter->Connect(left,right,left2,right2);
459 mExecuter->BeginPackage(words[1]);
463 mExecuter->EndPackage();
467 if (mFileName.size()>0)
469 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
473 mExecuter->Define(words[1],"",filename);
477 mExecuter->Define(words[1],words[2],filename);
482 mExecuter->EndDefine();
486 Print(words[1]); /// \todo use mExecuter
490 if (words[1]=="freeze")
491 mExecuter->SetNoExecMode(true);
492 else if (words[1]=="unfreeze")
493 mExecuter->SetNoExecMode(false);
495 mExecuter->Update(words[1]);
499 Utilities::SplitAroundFirstDot(words[2],left,right);
500 mExecuter->DefineInput(words[1],left,right,words[3]);
504 Utilities::SplitAroundFirstDot(words[2],left,right);
505 mExecuter->DefineOutput(words[1],left,right,words[3]);
509 Utilities::SplitAroundFirstDot(words[1],left,right);
510 mExecuter->Set(left,right,words[2]);
514 mExecuter->Author(words[1]);
518 mExecuter->Category(words[1]);
523 Index("tmp_index.html");
524 else if (words.size()==2)
526 else if (words.size()==3)
527 Index(words[1],words[2]);
531 mExecuter->Description(words[1]);
541 bbtk::MessageManager::PrintInfo();
545 sscanf(words[2].c_str(),"%d",&level);
546 bbtk::MessageManager::SetMessageLevel(words[1],level);
559 this->mExecuter->Reset();
565 InterpretFile(words[1], true ); // true : better pass use_config_file
569 SwitchToFile(words[1], true ); // true : better pass use_config_file
571 // if 'source' was given
574 this->mExecuter->SetCurrentFileName(words[1]);
579 LoadPackage(words[1], true ); // true : better pass use_config_file
583 UnLoadPackage(words[1]);
588 throw QuitException();
592 if (words.size() == 2)
594 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
595 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
599 mExecuter->SetWorkspaceName(words[2]);
604 bbtkInternalError("should not reach here !!!");
607 bbtkDecTab("Interpreter",9);
609 //=======================================================================
615 //=======================================================================
619 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
621 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
623 std::string delimiters = "\"";
624 std::vector<std::string> quote;
625 Utilities::SplitString(str,delimiters,quote);
628 std::vector<std::string>::iterator i;
629 for (i=quote.begin(); i!=quote.end(); )
631 Utilities::SplitString(*i,delimiters,tokens);
635 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
636 tokens.push_back(*i);
641 for (i=tokens.begin(); i!=tokens.end(); ++i)
643 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
645 bbtkDebugMessageCont("Interpreter",9,std::endl);
647 bbtkDebugDecTab("Interpreter",9);
649 //=======================================================================
652 //=======================================================================
653 // Replaces substrings "\\n" by a real carriage return "\n"
654 void SubsBackslashN ( std::string& s )
656 std::string ss("\\n");
657 std::string::size_type pos = 0;
660 while ( pos != std::string::npos )
662 s.replace(pos,2,cr,1);
663 pos = s.find(ss, pos-1);
666 //=======================================================================
669 //=======================================================================
673 void Interpreter::Print( const std::string& str)
675 if (mExecuter->GetNoExecMode()) return;
677 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
679 std::vector<std::string> chains;
680 std::string delimiters("$");
682 // Skip delimiters at beginning.
683 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
685 if (lastPos>0) is_text = false;
687 // Find first delimiter.
688 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
690 while (std::string::npos != pos || std::string::npos != lastPos)
694 // Found a text token, add it to the vector.
695 chains.push_back(str.substr(lastPos, pos - lastPos));
699 // is an output (between $$) : decode
700 std::string tok,box,output;
701 tok = str.substr(lastPos, pos - lastPos);
702 Utilities::SplitAroundFirstDot(tok,box,output);
703 chains.push_back( mExecuter->Get(box,output) );
705 // Skip delimiters. Note the "not_of"
706 lastPos = str.find_first_not_of(delimiters, pos);
707 // Find next delimiter
708 pos = str.find_first_of(delimiters, lastPos);
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 )
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 std::vector<std::string> script_paths;
747 std::string fullPathScriptName; // full path script name
748 std::string pkgname; // e.g. <scriptname>.bbs
749 std::vector<std::string> Filenames;
751 if (use_configuration_file)
753 // The following is *NOT* a debug time message :
754 // It's a user intended message.
755 // Please don't remove it.
756 bbtkMessage("Interpreter",1,
757 "look for : [" << name
758 << "] (use_configuration_file == TRUE)" << std::endl);
759 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
762 pkgname = Utilities::ExtractScriptName(name,upath);
764 bool fullnameGiven = false;
765 bool foundFile = false;
767 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
771 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
773 int nbFiles = Utilities::Explore(upath, false, Filenames);
775 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
777 if ((*i).substr((*i).size()-4, 4) != ".bbs")
778 continue; // ignore non .bbs files
783 bbtkMessage("Interpreter",2,
784 "WARNING : No '.bbs' file found in ["
785 << upath << "]" << std::endl);
790 std::vector<std::string>::iterator i;
791 std::string fullDirectoryName;
792 for (i=script_paths.begin();i!=script_paths.end();++i)// ==== relative name, iterate + load all .bbs files
796 // we *really* want '.' to be the current working directory
798 char buf[2048]; // for getcwd
799 char * currentDir = getcwd(buf, 2048);
800 std::string cwd(currentDir);
804 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
806 // Check if library exists
807 if ( ! Utilities::IsDirectory(fullDirectoryName) )
809 // The following is *NOT* a debug time message :
810 // It's a user intended message.
811 // Please don't remove it.
812 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
813 <<"] : doesn't exist" <<std::endl);
814 continue; // try next path
819 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
822 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
825 if ((*i).substr((*i).size()-4, 4) != ".bbs")
826 continue; // ignore non .bbs files
831 bbtkMessage("Interpreter",1,
832 "WARNING : No '.bbs' file found in ["
833 << fullDirectoryName << "]" << std::endl);
835 //break; // a directory was found; we stop iterating
836 // LG : No! We want all files included !
841 //std::string::size_type slash_position = name.find_last_of("/\\");
843 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
844 // (not only a plain script name)
845 // we trust him, and try to expland the directory name
846 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
848 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
851 // ===========================================================check user supplied location
852 fullnameGiven = true;
854 fullPathScriptName = Utilities::ExpandLibName(name, false);
856 // allow user to always forget ".bbs"
857 int l = fullPathScriptName.size();
863 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
865 fullPathScriptName = fullPathScriptName + ".bbs";
870 fullPathScriptName = fullPathScriptName + ".bbs";
873 if ( Utilities::FileExists(fullPathScriptName))
881 // =============================================================== iterate on the paths
884 std::vector<std::string>::iterator i;
885 for (i=script_paths.begin();i!=script_paths.end();++i)
889 // we *really* want '.' to be the current working directory
891 char buf[2048]; // for getcwd
892 char * currentDir = getcwd(buf, 2048);
893 std::string cwd(currentDir);
897 // fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true); //pkgname);
899 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
902 // Check if library exists
903 if ( ! Utilities::FileExists(fullPathScriptName) )
905 // The following is *NOT* a debug time message :
906 // It's a user intended message.
907 // Please don't remove it.
908 bbtkMessage("Interpreter",2,
909 " [" <<fullPathScriptName <<"] : doesn't exist"
911 continue; // try next path
913 bbtkMessage("Interpreter",2,
914 " [" <<fullPathScriptName
915 <<"] : found" <<std::endl);
917 break; // a script was found; we stop iterating
919 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
925 if(fullPathScriptName == "")
926 bbtkError("Path ["<<upath<<"] doesn't exist");
928 bbtkError("Script ["<<fullPathScriptName<<"] not found");
930 bbtkError("No ["<<pkgname<<".bbs] script found");
934 LoadScript(fullPathScriptName,name);
940 //=======================================================================
942 void Interpreter::LoadScript( std::string fullPathScriptName,
943 std::string includeScriptName)
945 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)
948 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
949 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
954 s = new std::ifstream;
955 s->open(fullPathScriptName.c_str());
958 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
962 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
963 << "] found" << std::endl);
966 mFileName.push_back(fullPathScriptName);
967 mIncludeFileName.push_back(includeScriptName);
972 //=======================================================================
976 void Interpreter::CloseCurrentFile()
978 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
983 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
987 mFile.back()->close();
990 bbtkDebugMessage("Interpreter",9,
991 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
993 mFileName.pop_back();
994 mIncludeFileName.pop_back();
996 bbtkDebugMessage("Interpreter",9," Remains "
998 <<" open"<<std::endl);
999 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1002 //=======================================================================
1004 //=======================================================================
1008 void Interpreter::CloseAllFiles()
1010 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1013 while (mFile.size() != 0)
1015 mFile.back()->close();
1016 delete mFile.back();
1018 bbtkDebugMessage("Interpreter",9,
1019 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1020 mFileName.pop_back();
1021 mIncludeFileName.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 category
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]);
1087 #ifdef _USE_WXWIDGETS_
1088 if ( WxConsole::GetInstance() != 0 )
1091 ConfigurationFile::GetInstance().Get_doc_path();
1092 url += "/bbdoc/" + words[1] + "/index.html";
1093 if (Utilities::FileExists(url))
1095 WxConsole::GetInstance()->ShowHtmlPage(url);
1100 catch (bbtk::Exception f)
1104 std::string package;
1105 HelpBlackBox(words[1],package);
1106 #ifdef _USE_WXWIDGETS_
1107 if ( WxConsole::GetInstance() != 0 )
1110 ConfigurationFile::GetInstance().Get_doc_path();
1111 url += "/bbdoc/" + package + "/index.html";
1112 if (Utilities::FileExists(url))
1114 url += "#" + words[1];
1115 WxConsole::GetInstance()->ShowHtmlPage(url);
1120 catch (bbtk::Exception g)
1124 this->mExecuter->ShowRelations(words[1],"0","9999");
1126 catch (bbtk::Exception h){
1127 bbtkError("\""<<words[1].c_str()
1128 <<"\" is not a known command, package, black box type or black box name");
1136 if (words[2]=="all")
1138 if ( words[1]=="packages" )
1140 PrintPackages(true,true);
1145 HelpPackage(words[1],true);
1147 catch (bbtk::Exception f)
1153 HelpCommand(words[0]);
1154 bbtkError(words[0]<<" : syntax error");
1159 bbtkError("Should not reach here !!!");
1162 //=======================================================================
1164 //===================================================================
1165 /// Displays the Configuration
1166 void Interpreter::Config() const
1168 ConfigurationFile::GetInstance().GetHelp(1);
1170 //===================================================================
1172 //=======================================================================
1173 /// Displays help on all the commands
1174 void Interpreter::HelpCommands()
1176 std::cout << "Available commands :" << std::endl;
1177 CommandDictType::iterator i;
1178 for ( i = mCommandDict.begin();
1179 i != mCommandDict.end();
1181 std::cout << " " << i->first << std::endl;
1182 // std::cout << " usage : " << i->second.syntax << std::endl;
1183 // std::cout << " " << i->second.help << std::endl;
1187 //=======================================================================
1190 //=======================================================================
1191 /// Displays help on a particular commands
1192 void Interpreter::HelpCommand(const std::string& s)
1194 CommandDictType::iterator c;
1195 c = mCommandDict.find(s);
1196 if ( c == mCommandDict.end() ) {
1197 bbtkError(s<<" : Unknown command");
1199 // std::cout << " " << s << " : "<< std::endl;
1200 // CommandParamDictType::iterator i;
1201 // for ( i = c->second.begin();
1202 // i != c->second.end();
1204 std::cout << " usage : " << c->second.syntax << std::endl;
1205 std::cout << " " << c->second.help << std::endl;
1208 //=======================================================================
1211 //=======================================================================
1212 /// Fills the vector commands with the commands which
1213 /// have the first n chars of buf for prefix
1214 /// TODO : skip initial spaces in buf and also return the position of first
1215 /// non blank char in buf
1216 void Interpreter::FindCommandsWithPrefix( char* buf,
1218 std::vector<std::string>& commands )
1220 CommandDictType::const_iterator i;
1221 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1223 if ((i->first).find(buf,0,n) == 0)
1224 commands.push_back(i->first);
1227 //=======================================================================
1231 //=======================================================================
1232 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1234 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1235 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1237 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1238 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1239 // E.G. STORE THIS IN bbtk_config.xml
1240 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1241 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1242 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1243 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1244 #define BBTK_BACKSPACE_KBCODE 0x00000008
1245 #define BBTK_DEL_KBCODE 0x0000007F
1246 #define BBTK_SPACE_KBCODE 0x00000020
1248 //=======================================================================
1249 void Interpreter::GetLineFromPrompt(std::string& s)
1254 int MAX_LINE_SIZE = 160;
1255 int MAX_HISTORY_SIZE = 100;
1257 char* newline = new char[MAX_LINE_SIZE];
1258 memset(newline,0,MAX_LINE_SIZE);
1259 char* histline = new char[MAX_LINE_SIZE];
1260 memset(histline,0,MAX_LINE_SIZE);
1262 char* line = newline;
1263 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 //=======================================================================