1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/17 07:04:08 $
7 Version: $Revision: 1.45 $
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"
30 #ifdef CMAKE_HAVE_TERMIOS_H
32 #define BBTK_USE_TERMIOS_BASED_PROMPT
40 //Interpreter* Interpreter::mGlobalInterpreter = NULL;
42 //=======================================================================
46 Interpreter::Interpreter()
48 #ifdef _USE_WXWIDGETS_
54 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
55 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
56 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
58 mExecuter = new bbtk::Executer();
59 mExecuter->SetInterpreter(this);
61 // For the time being, comment out previous line, and
62 // uncomment next line to check Transcriptor
64 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
66 // Builds the commands dict
69 info.category = "new";
73 info.syntax = "new <type> <name>";
74 info.help = "Creates a new black box of type <type> with name <name>";
75 mCommandDict[info.category] = info;
77 info.category = "delete";
81 info.syntax = "delete <box>";
82 info.help = "Deletes the black box of name <box>";
83 mCommandDict[info.category] = info;
85 info.category = "connect";
89 info.syntax = "connect <box1.output> <box2.input>";
90 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
91 mCommandDict[info.category] = info;
93 info.category = "print";
97 info.syntax = "print <string>";
98 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').";
99 mCommandDict[info.category] = info;
101 info.category = "exec";
105 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
106 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.";
107 mCommandDict[info.category] = info;
109 info.category = "package";
112 info.code = cPackage;
113 info.syntax = "package <name>";
114 info.help = "Begins the definition of a package.";
115 mCommandDict[info.category] = info;
117 info.category = "endpackage";
120 info.code = cEndPackage;
121 info.syntax = "endpackage";
122 info.help = "Ends the definition of a package.";
123 mCommandDict[info.category] = info;
125 info.category = "define";
129 info.syntax = "define <type> [<package>]";
130 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.";
131 mCommandDict[info.category] = info;
133 info.category = "endefine";
136 info.code = cEndDefine;
137 info.syntax = "endefine";
138 info.help = "Ends the definition of a new type of complex black box";
139 mCommandDict[info.category] = info;
141 info.category = "input";
145 info.syntax = "input <name> <box.input> <help>";
146 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";
147 mCommandDict[info.category] = info;
149 info.category = "output";
153 info.syntax = "output <name> <box.output> <help>";
154 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";
155 mCommandDict[info.category] = info;
157 info.category = "set";
161 info.syntax = "set <box.input> <value>";
162 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";
163 mCommandDict[info.category] = info;
165 info.category = "config"; // JPR
169 info.syntax = "config";
170 info.help = "Prints the value of all configuration parameters";
171 mCommandDict[info.category] = info;
173 info.category = "index"; // LG
178 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
179 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. If 'Adaptors' is provided then an alphabetical index of all adaptors is created.";
180 mCommandDict[info.category] = info;
182 info.category = "reset";
186 info.syntax = "reset";
187 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
188 mCommandDict[info.category] = info;
190 info.category = "author";
194 info.syntax = "author <string>";
195 info.help = "Adds the string <string> to the author information of the black box being defined";
196 mCommandDict[info.category] = info;
198 info.category = "category"; //JP
201 info.code = cCategory;
202 info.syntax = "category <list of items, separated by ;>";
203 info.help = "Adds the string <string> to the category information of the black box being defined";
204 mCommandDict[info.category] = info;
206 info.category = "description";
209 info.code = cDescription;
210 info.syntax = "description <string>";
211 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
212 mCommandDict[info.category] = info;
214 info.category = "help";
218 info.syntax = "help";
219 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>";
220 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.";
221 mCommandDict[info.category] = info;
223 info.category = "message";
226 info.code = cMessage;
227 info.syntax = "message <kind> <level>";
228 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;
230 info.category = "include";
233 info.code = cInclude;
234 info.syntax = "include <filename> [source]";
235 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).";
236 mCommandDict[info.category] = info;
238 info.category = "quit";
242 info.syntax = "quit";
243 info.help = "Quits the program (during script execution it stops the complete execution)";
244 mCommandDict[info.category] = info;
246 info.category = "load";
250 info.syntax = "load <packagename>";
251 info.help = "Loads the black box package <packagename>";
252 mCommandDict[info.category] = info;
254 info.category = "unload";
258 info.syntax = "unload <packagename>";
259 info.help = "Unloads the black box package <packagename>";
260 mCommandDict[info.category] = info;
262 info.category = "graph";
266 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 ]]]]]]";
267 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')";
268 mCommandDict[info.category] = info;
271 info.category = "workspace";
274 info.code = cWorkspace;
275 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
276 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.";
277 mCommandDict[info.category] = info;
280 bbtkDebugDecTab("Interpreter",9);
283 //=======================================================================
287 //=======================================================================
291 Interpreter::~Interpreter()
293 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
296 bbtkDebugDecTab("Interpreter",9);
298 //=======================================================================
301 //=======================================================================
305 void Interpreter::InterpretFile( const std::string& filename )
307 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
308 // std::cout << "==========================================Entree InterpretFile ["<<filename<<"] try SwitchToFile "<<std::endl;
309 bool exm = mCommandLine;
310 mCommandLine = false;
314 SwitchToFile(filename);
317 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
319 std::cout << "A=== [" << (*it) << "]" << std::endl;
322 bool insideComment = false; // for multiline comment
323 while (mFile.size()>0)
326 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
328 std::cout << "B=== [" << (*it) << "]" << std::endl;
332 //while ((mFile.size()>0) && !mFile.back()->eof() )
334 // std::cout << "mFile.size() "<< mFile.size() << " mFileName.back() [" << mFileName.back() << "]" << std::endl;
335 while (!mFile.back()->eof()) {
338 mFile.back()->getline(buf,500);
339 std::string str(buf);
340 // std::cout << " in InterpretFile mFile.back()->getline [" << str << "]" << std::endl;
341 int size=str.length();
342 if ( str[ size-1 ]==13 )
347 InterpretLine(str, insideComment);
350 //if (mFile.size()>0)
354 catch (QuitException e)
357 catch (bbtk::Exception e)
359 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
360 if (mFileName.size()) {
361 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
362 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
365 catch (std::exception& e)
367 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
368 if (mFileName.size()) {
369 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
370 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
375 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
376 if (mFileName.size()) {
377 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
378 std::cout << "* LINE : "<<mLine.back()<<std::endl;
383 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
384 bbtkDecTab("Interpreter",9);
388 //=======================================================================
392 //=======================================================================
396 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
398 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
399 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
401 std::vector<std::string> words;
402 SplitLine(line,words);
407 bbtkDebugDecTab("Interpreter",9);
411 // Single line comment : # or //
412 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
414 bbtkDebugDecTab("Interpreter",9);
415 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
419 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
421 if (words[0][0]=='/' && words[0][1]=='*')
423 bbtkDebugDecTab("Interpreter",9);
424 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
425 insideComment = true;
429 if (words[0][0]=='*' && words[0][1]=='/')
431 bbtkDebugDecTab("Interpreter",9);
432 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
433 if ( !insideComment ) {
434 bbtkDebugDecTab("Interpreter",9);
435 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
437 insideComment = false;
443 bbtkDebugDecTab("Interpreter",9);
444 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
449 CommandInfoType command;
450 InterpretCommand(words,command);
452 bbtkDebugMessage("Interpreter",9,
453 "Command='"<<command.category
454 <<"' code="<<command.code<<std::endl);
456 std::string left,right,left2,right2;
457 std::string filename;
458 switch (command.code)
461 mExecuter->Create(words[1],words[2]);
466 // mExecuter->Remove(words[1]);
470 Utilities::SplitAroundFirstDot(words[1],left,right);
471 Utilities::SplitAroundFirstDot(words[2],left2,right2);
472 mExecuter->Connect(left,right,left2,right2);
476 mExecuter->BeginPackage(words[1]);
480 mExecuter->EndPackage();
484 if (mFileName.size()>0)
486 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
490 mExecuter->Define(words[1],"",filename);
494 mExecuter->Define(words[1],words[2],filename);
499 mExecuter->EndDefine();
503 Print(words[1]); /// \todo use generate command
507 if (words[1]=="freeze")
508 mExecuter->SetNoExecMode(true);
509 else if (words[1]=="unfreeze")
510 mExecuter->SetNoExecMode(false);
512 mExecuter->Update(words[1]);
516 Utilities::SplitAroundFirstDot(words[2],left,right);
517 mExecuter->DefineInput(words[1],left,right,words[3]);
521 Utilities::SplitAroundFirstDot(words[2],left,right);
522 mExecuter->DefineOutput(words[1],left,right,words[3]);
526 Utilities::SplitAroundFirstDot(words[1],left,right);
527 mExecuter->Set(left,right,words[2]);
531 mExecuter->Author(words[1]);
535 mExecuter->Category(words[1]);
540 Index("tmp_index.html");
541 else if (words.size()==2)
543 else if (words.size()==3)
544 Index(words[1],words[2]);
548 mExecuter->Description(words[1]);
558 bbtk::MessageManager::PrintInfo();
562 sscanf(words[2].c_str(),"%d",&level);
563 bbtk::MessageManager::SetMessageLevel(words[1],level);
576 this->mExecuter->Reset();
582 InterpretFile(words[1]);
586 SwitchToFile(words[1]);
588 // if 'source' was given
591 GetExecuter()->SetCurrentFileName(words[1]);
596 GetExecuter()->GetFactory()->LoadPackage(words[1]);
600 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
605 throw QuitException();
609 if (words.size() == 2)
611 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
612 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
616 mExecuter->SetWorkspaceName(words[2]);
621 bbtkInternalError("should not reach here !!!");
624 bbtkDecTab("Interpreter",9);
626 //=======================================================================
632 //=======================================================================
636 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
638 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
640 std::string delimiters = "\"";
641 std::vector<std::string> quote;
642 Utilities::SplitString(str,delimiters,quote);
645 std::vector<std::string>::iterator i;
646 for (i=quote.begin(); i!=quote.end(); )
648 Utilities::SplitString(*i,delimiters,tokens);
652 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
653 tokens.push_back(*i);
658 for (i=tokens.begin(); i!=tokens.end(); ++i)
660 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
662 bbtkDebugMessageCont("Interpreter",9,std::endl);
664 bbtkDebugDecTab("Interpreter",9);
666 //=======================================================================
669 //=======================================================================
670 // Replaces substrings "\\n" by a real carriage return "\n"
671 void SubsBackslashN ( std::string& s )
673 std::string ss("\\n");
674 std::string::size_type pos = 0;
677 while ( pos != std::string::npos )
679 s.replace(pos,2,cr,1);
680 pos = s.find(ss, pos-1);
683 //=======================================================================
686 //=======================================================================
690 void Interpreter::Print( const std::string& str)
692 if (mExecuter->GetNoExecMode()) return;
694 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
697 // InterpretLine ("load std")
698 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
699 // InterpretLine("new Print _P_")
700 // InterpretLine("connect _C_.Out _P_.In")
704 std::vector<std::string> chains;
705 std::string delimiters("$");
707 // Skip delimiters at beginning.
708 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
710 if (lastPos>0) is_text = false;
712 // Find first delimiter.
713 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
715 while (std::string::npos != pos || std::string::npos != lastPos)
719 // Found a text token, add it to the vector.
720 chains.push_back(str.substr(lastPos, pos - lastPos));
721 // std::string token = str.substr(lastPos, pos - lastPos)
722 // InterpretLine("set _C_.In%num% %token%")
728 // is an output (between $$) : decode
729 std::string tok,box,output;
730 tok = str.substr(lastPos, pos - lastPos);
731 Utilities::SplitAroundFirstDot(tok,box,output);
732 chains.push_back( mExecuter->Get(box,output) );
734 // InterpretLine("connect %tok% _C_.In%num%")
737 // Skip delimiters. Note the "not_of"
738 lastPos = str.find_first_not_of(delimiters, pos);
739 // Find next delimiter
740 pos = str.find_first_of(delimiters, lastPos);
745 // InterpretLine("exec _P_")
746 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
748 std::vector<std::string>::iterator i;
749 for (i= chains.begin(); i!=chains.end(); ++i)
751 // bbtkMessage("Echo",1,*i);
755 std::cout << std::endl;
756 bbtkDebugDecTab("Interpreter",9);
759 //=======================================================================
764 // ===================================================================================
766 void Interpreter::SwitchToFile( const std::string& name )
768 // Note : in the following :
769 // name : the user supplied name
770 // - abreviated name e.g. scr scr.bbs
771 // - relative full name e.g. ./scr.bbs ../../scr.bbs
772 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
773 // same for Windows, with c:, d: ...
775 // use ./directory/subdir/scrname.bbs
778 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
779 <<name<<"\")"<<std::endl);
781 std::vector<std::string> script_paths;
782 std::string fullPathScriptName; // full path script name
783 std::string pkgname; // e.g. <scriptname>.bbs
784 std::vector<std::string> Filenames;
786 // The following is *NOT* a debug time message :
787 // It's a user intended message.
788 // Please don't remove it.
789 bbtkMessage("Interpreter",1,
790 "look for : [" << name
791 << "]" << std::endl);
792 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
795 pkgname = Utilities::ExtractScriptName(name,upath);
797 bbtkMessage("Interpreter",1,
798 "extract : pkgname [" << pkgname
799 << "] upath [" << upath << "]" << std::endl);
800 bool fullnameGiven = false;
801 bool foundFile = false;
803 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
805 // std::cout << "JPR================== * found, load all boxes " << std::endl;
808 std::stringstream* stream = new std::stringstream;
809 //if (upath.size()!=0) // avoid troubles for "*"
811 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
813 // std::cout << "JPR================== absolute name, load all .bbs files " << std::endl;
814 int nbFiles = Utilities::Explore(upath, false, Filenames);
816 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
818 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
819 int lgr = (*i).size();
821 continue; // ignore non .bbs file
822 if ((*i).substr(lgr-4, 4) != ".bbs")
825 if (lgr > 10) // 10 -> '-appli.bbs'
827 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
828 continue; // ignore '-appli.bbs' files
832 (*stream) << "include " << *i << "\n";
833 //EED InterpretFile(*i);
838 bbtkMessage("Interpreter",2,
839 "WARNING : No '.bbs' file found in ["
840 << upath << "]" << std::endl);
842 SwitchToStream(stream);
848 std::vector<std::string>::iterator i;
849 std::string fullDirectoryName;
850 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
854 // we *really* want '.' to be the current working directory
856 char buf[2048]; // for getcwd
857 char * currentDir = getcwd(buf, 2048);
858 std::string cwd(currentDir);
862 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
864 // without last slash "\"
865 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
867 // Check if library exists
868 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
870 // The following is *NOT* a debug time message :
871 // It's a user intended message.
872 // Please don't remove it.
873 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
874 <<"] : doesn't exist" <<std::endl);
875 continue; // try next path
880 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
883 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
885 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
886 int lgr = (*i).size();
888 continue; // ignore non .bbs file
889 if ((*i).substr(lgr-4, 4) != ".bbs")
892 if (lgr > 10) // 10 -> '-appli.bbs'
894 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
895 continue; // ignore '-appli.bbs' files
899 (*stream) << "include " << *i << "\n";
900 //EED InterpretFile(*i);
905 bbtkMessage("Interpreter",1,
906 "WARNING : No '.bbs' file found in ["
907 << fullDirectoryName << "]" << std::endl);
909 SwitchToStream(stream);
912 //break; // a directory was found; we stop iterating
913 // LG : No! We want all files included !
918 //std::string::size_type slash_position = name.find_last_of("/\\");
920 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
921 // (not only a plain script name)
922 // we trust him, and try to expland the directory name
923 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
925 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
928 // ===========================================================check user supplied location
929 fullnameGiven = true;
931 fullPathScriptName = Utilities::ExpandLibName(name, false);
933 // allow user to always forget ".bbs"
934 int l = fullPathScriptName.size();
940 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
942 fullPathScriptName = fullPathScriptName + ".bbs";
947 fullPathScriptName = fullPathScriptName + ".bbs";
950 if ( Utilities::FileExists(fullPathScriptName))
957 // =============================================================== iterate on the paths
960 std::vector<std::string>::iterator i;
961 for (i=script_paths.begin();i!=script_paths.end();++i)
964 // we *really* want '.' to be the current working directory
966 char buf[2048]; // for getcwd
967 char * currentDir = getcwd(buf, 2048);
968 std::string cwd(currentDir);
972 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
974 // Check if library exists
975 if ( ! Utilities::FileExists(fullPathScriptName) )
977 // The following is *NOT* a debug time message :
978 // It's a user intended message.
979 // Please don't remove it.
980 bbtkMessage("Interpreter",2,
981 " [" <<fullPathScriptName <<"] : doesn't exist"
983 continue; // try next path
985 bbtkMessage("Interpreter",2,
986 " [" <<fullPathScriptName
987 <<"] : found" <<std::endl);
989 break; // a script was found; we stop iterating
991 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
997 if(fullPathScriptName == "")
998 bbtkError("Path ["<<upath<<"] doesn't exist");
1000 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1002 bbtkError("No ["<<pkgname<<".bbs] script found");
1006 LoadScript(fullPathScriptName,name);
1012 void Interpreter::SwitchToStream( std::stringstream* stream )
1014 //std::cout << "== 1 Entry in Interpreter::SwitchToStream " << std::endl;
1016 mFile.push_back(stream);
1017 //std::cout << " mFile.size() " << mFile.size() << std::endl;
1018 std::ostringstream buffer_name;
1020 buffer_name << "buffer_" ; // << bufferNb;
1022 // std::cout << " mFile.size() " << mFile.size() << std::endl;
1023 // std::cout << " mFileName.size() " << mFileName.size() << std::endl;
1024 // std::cout << " mLine.size() " << mLine.size() << std::endl;
1025 // std::vector<std::string>::iterator j = mFileName.begin();
1026 // std::cout << " mFileName.begin() succeeded" << std::endl;
1027 // std::cout << " mFileName[0] " << mFileName[0] << std::endl;
1028 //std::cout << " mFileName.begin() " << mFileName.begin() << std::endl;
1030 for( std::vector<std::string>::iterator i = mFileName.begin(); i!= mFileName.end(); ++i)
1033 std::cout << "Interpreter::SwitchToStream : mFileName [" << *i << "]" << std::endl;
1036 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1037 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1039 if (mFileName.size()>0 )// && (mFile.size()>0) ) // NO!!!
1041 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1042 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1043 buffer_name << mFileName.back() << "_" << mLine.back();
1045 //std::cout << "3 in Interpreter::SwitchToStream buffer_name :[" << buffer_name.str() << "]" << std::endl;
1046 mFileName.push_back(buffer_name.str());
1047 mIncludeFileName.push_back(buffer_name.str());
1051 //=======================================================================
1053 void Interpreter::LoadScript( std::string fullPathScriptName,
1054 std::string includeScriptName)
1056 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1058 bool okScriptExist=false;
1059 int iStrScript,sizeVecStricpt=mFileName.size();
1060 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1062 if (mFileName[iStrScript] == fullPathScriptName )
1068 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1069 // if (okScriptExist==true)
1071 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1072 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1077 s = new std::ifstream;
1078 s->open(fullPathScriptName.c_str());
1081 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1085 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1086 << "] found" << std::endl);
1089 mFileName.push_back(fullPathScriptName);
1090 mIncludeFileName.push_back(includeScriptName);
1095 //=======================================================================
1099 void Interpreter::CloseCurrentFile()
1101 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1104 if (mFile.size()==0)
1106 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1110 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1112 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1113 if (file!=0) file->close();
1115 delete mFile.back();
1117 mFileName.pop_back();
1118 mIncludeFileName.pop_back();
1121 bbtkDebugMessage("Interpreter",9," Remains "
1123 <<" open"<<std::endl);
1124 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1127 //=======================================================================
1129 //=======================================================================
1133 void Interpreter::CloseAllFiles()
1135 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1138 while (mFile.size() != 0)
1142 mFile.back()->close();
1143 delete mFile.back();
1145 bbtkDebugMessage("Interpreter",9,
1146 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1147 mFileName.pop_back();
1148 mIncludeFileName.pop_back();
1152 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1155 //=======================================================================
1159 //=======================================================================
1163 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1164 CommandInfoType& info )
1166 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1168 // searches the command category
1169 CommandDictType::iterator c;
1170 c = mCommandDict.find(words[0]);
1171 if ( c == mCommandDict.end() ) {
1172 bbtkError(words[0]<<" : unknown command");
1175 // tests the number of args
1176 if ( ( words.size()-1 < c->second.argmin ) ||
1177 ( words.size()-1 > c->second.argmax ) )
1179 HelpCommand(words[0]);
1180 bbtkError(words[0]<<" : wrong number of arguments");
1184 bbtkDecTab("Interpreter",9);
1186 //=======================================================================
1189 //=======================================================================
1190 /// Displays help on all the commands
1191 void Interpreter::Help(const std::vector<std::string>& words)
1193 unsigned int nbarg = words.size()-1;
1201 if (words[1]=="packages")
1203 GetExecuter()->GetFactory()->PrintPackages(true);
1208 HelpCommand(words[1]);
1210 catch (bbtk::Exception e)
1214 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1215 #ifdef _USE_WXWIDGETS_
1216 if ( mWxConsole != 0 )
1219 ConfigurationFile::GetInstance().Get_doc_path();
1220 url += "/bbdoc/" + words[1] + "/index.html";
1221 if (Utilities::FileExists(url))
1223 mWxConsole->ShowHtmlPage(url);
1228 catch (bbtk::Exception f)
1232 std::string package;
1233 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1234 #ifdef _USE_WXWIDGETS_
1235 if ( mWxConsole != 0 )
1238 ConfigurationFile::GetInstance().Get_doc_path();
1239 url += "/bbdoc/" + package + "/index.html";
1240 if (Utilities::FileExists(url))
1242 url += "#" + words[1];
1243 mWxConsole->ShowHtmlPage(url);
1248 catch (bbtk::Exception g)
1252 GetExecuter()->ShowRelations(words[1],"0","9999");
1254 catch (bbtk::Exception h){
1255 bbtkError("\""<<words[1].c_str()
1256 <<"\" is not a known command, package, black box type or black box name");
1264 if (words[2]=="all")
1266 if ( words[1]=="packages" )
1268 GetExecuter()->GetFactory()->PrintPackages(true,true);
1273 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1275 catch (bbtk::Exception f)
1281 HelpCommand(words[0]);
1282 bbtkError(words[0]<<" : syntax error");
1287 bbtkError("Should not reach here !!!");
1290 //=======================================================================
1292 //===================================================================
1293 /// Displays the Configuration
1294 void Interpreter::Config() const
1296 ConfigurationFile::GetInstance().GetHelp(1);
1298 //===================================================================
1300 //=======================================================================
1301 /// Displays help on all the commands
1302 void Interpreter::HelpCommands()
1304 std::cout << "Available commands :" << std::endl;
1305 CommandDictType::iterator i;
1306 for ( i = mCommandDict.begin();
1307 i != mCommandDict.end();
1309 std::cout << " " << i->first << std::endl;
1310 // std::cout << " usage : " << i->second.syntax << std::endl;
1311 // std::cout << " " << i->second.help << std::endl;
1315 //=======================================================================
1318 //=======================================================================
1319 /// Displays help on a particular commands
1320 void Interpreter::HelpCommand(const std::string& s)
1322 CommandDictType::iterator c;
1323 c = mCommandDict.find(s);
1324 if ( c == mCommandDict.end() ) {
1325 bbtkError(s<<" : Unknown command");
1327 // std::cout << " " << s << " : "<< std::endl;
1328 // CommandParamDictType::iterator i;
1329 // for ( i = c->second.begin();
1330 // i != c->second.end();
1332 std::cout << " usage : " << c->second.syntax << std::endl;
1333 std::cout << " " << c->second.help << std::endl;
1336 //=======================================================================
1339 //=======================================================================
1340 /// Fills the vector commands with the commands which
1341 /// have the first n chars of buf for prefix
1342 /// TODO : skip initial spaces in buf and also return the position of first
1343 /// non blank char in buf
1344 void Interpreter::FindCommandsWithPrefix( char* buf,
1346 std::vector<std::string>& commands )
1348 CommandDictType::const_iterator i;
1349 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1351 if ((i->first).find(buf,0,n) == 0)
1352 commands.push_back(i->first);
1355 //=======================================================================
1359 //=======================================================================
1360 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1362 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1363 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1365 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1366 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1367 // E.G. STORE THIS IN bbtk_config.xml
1368 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1369 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1370 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1371 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1372 #define BBTK_BACKSPACE_KBCODE 0x00000008
1373 #define BBTK_DEL_KBCODE 0x0000007F
1374 #define BBTK_SPACE_KBCODE 0x00000020
1376 //=======================================================================
1377 void Interpreter::GetLineFromPrompt(std::string& s)
1382 int MAX_LINE_SIZE = 160;
1383 int MAX_HISTORY_SIZE = 100;
1385 char* newline = new char[MAX_LINE_SIZE];
1386 memset(newline,0,MAX_LINE_SIZE);
1387 char* histline = new char[MAX_LINE_SIZE];
1388 memset(histline,0,MAX_LINE_SIZE);
1390 char* line = newline;
1391 int hist = mHistory.size();
1397 read ( STDIN_FILENO, &c, 4) ;
1399 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1401 // Printable character
1402 if ( (ind<MAX_LINE_SIZE-1) &&
1403 ( c >= BBTK_SPACE_KBCODE ) &&
1404 ( c < BBTK_DEL_KBCODE ))
1412 // delete the unused line
1418 // empty lines are not stored in from history
1421 // if history too long : delete oldest command
1422 if (mHistory.size()>MAX_HISTORY_SIZE)
1424 delete mHistory.front();
1425 mHistory.pop_front();
1427 mHistory.push_back(line);
1432 else if ( (ind>0) &&
1433 ((c == BBTK_BACKSPACE_KBCODE) ||
1434 (c == BBTK_DEL_KBCODE)) )
1442 // TODO : Command completion
1443 std::vector<std::string> commands;
1444 FindCommandsWithPrefix( line,ind,commands);
1445 if (commands.size()==1)
1447 std::string com = *commands.begin();
1448 for (; ind<com.size(); ++ind)
1450 PrintChar(com[ind]);
1456 else if (commands.size()>1)
1458 std::vector<std::string>::iterator i;
1460 for (i=commands.begin();i!=commands.end();++i)
1462 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1465 write(STDOUT_FILENO,"\n> ",3);
1466 //for (int j=0;j<ind;++j)
1468 write(STDOUT_FILENO,line,ind);
1472 // Arrow up : back in history
1473 else if (c==BBTK_UP_ARROW_KBCODE)
1477 // erase current line
1478 while (ind--) BackSpace();
1482 strcpy(histline,mHistory[hist]);
1486 write(STDOUT_FILENO,line,ind);
1489 // Arrow down : down in history
1490 else if (c==BBTK_DOWN_ARROW_KBCODE)
1492 if (hist<mHistory.size()-1)
1494 // erase current line
1495 while (ind--) BackSpace();
1499 strcpy(histline,mHistory[hist]);
1503 write(STDOUT_FILENO,line,ind);
1505 // end of history : switch back to newline
1506 else if (hist==mHistory.size()-1)
1508 // erase current line
1509 while (ind--) BackSpace();
1516 write(STDOUT_FILENO,line,ind);
1520 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1522 PrintChar(line[ind]);
1527 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1535 write(STDOUT_FILENO,"\n\r",2);
1543 //=======================================================================
1544 void Interpreter::GetLineFromPrompt(std::string& s)
1570 //=======================================================================
1576 //=======================================================================
1577 void Interpreter::CommandLineInterpreter()
1579 bbtkDebugMessageInc("Interpreter",9,
1580 "Interpreter::CommandLineInterpreter()"<<std::endl);
1582 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1583 // Initialise the tty in non canonical mode with no echo
1584 // oter remembers the previous settings to restore them after
1585 struct termios ter,oter;
1588 ter.c_lflag &= ~ECHO;
1589 ter.c_lflag &= ~ICANON;
1592 tcsetattr(0,TCSANOW,&ter);
1595 mCommandLine = true;
1597 bool insideComment = false; // for multiline comment
1603 GetLineFromPrompt(line);
1604 InterpretLine(line, insideComment);
1606 catch (QuitException e)
1610 catch (bbtk::Exception e)
1614 catch (std::exception& e)
1616 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1620 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1625 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1626 tcsetattr(0,TCSANOW,&oter);
1629 std::cout << "Good bye !" << std::endl;
1631 bbtkDebugDecTab("Interpreter",9);
1634 //=======================================================================
1635 void Interpreter::Graph(const std::vector<std::string>& words)
1638 bool system_display = true;
1640 #ifdef _USE_WXWIDGETS_
1641 if ( mWxConsole != 0 ) system_display = false;
1644 if (words.size()==1)
1646 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1648 else if (words.size()==2)
1650 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1652 else if (words.size()==3)
1654 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1656 else if (words.size()==4)
1658 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1660 else if (words.size()==5)
1662 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1664 else if (words.size()==6)
1666 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1668 else if (words.size()==7)
1670 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1673 #ifdef _USE_WXWIDGETS_
1674 if ( mWxConsole != 0 )
1675 mWxConsole->ShowHtmlPage(page);
1678 //=======================================================================
1681 //=======================================================================
1682 void Interpreter::Index(const std::string& filename,
1683 const std::string& type)
1685 Factory::IndexEntryType t;
1686 if (type=="Initials") t = Factory::Initials;
1687 else if (type=="Categories") t = Factory::Categories;
1688 else if (type=="Packages") t = Factory::Packages;
1689 else if (type=="Adaptors") t = Factory::Adaptors;
1691 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1693 //=======================================================================