1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/19 14:58:13 $
7 Version: $Revision: 1.47 $
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 Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
307 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
309 bool exm = mCommandLine;
310 mCommandLine = false;
312 ExitStatus status = OK;
316 SwitchToFile(filename);
317 bool insideComment = false; // for multiline comment
318 while (mFile.size()>0)
320 while (!mFile.back()->eof()) {
323 mFile.back()->getline(buf,500);
324 std::string str(buf);
325 int size=str.length();
326 if ( str[ size-1 ]==13 )
331 InterpretLine(str, insideComment);
337 catch (QuitException e)
341 catch (bbtk::Exception e)
343 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
344 if (mFileName.size()) {
345 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
346 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
350 catch (std::exception& e)
352 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
353 if (mFileName.size()) {
354 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
355 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
361 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
362 if (mFileName.size()) {
363 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
364 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
370 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
371 bbtkDecTab("Interpreter",9);
377 //=======================================================================
380 //=======================================================================
384 Interpreter::ExitStatus
385 Interpreter::InterpretBuffer( std::stringstream* buffer )
387 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
389 bool exm = mCommandLine;
390 mCommandLine = false;
392 ExitStatus status = OK;
396 SwitchToStream(buffer);
397 bool insideComment = false; // for multiline comment
398 while (mFile.size()>0)
400 while (!mFile.back()->eof()) {
403 mFile.back()->getline(buf,500);
404 std::string str(buf);
406 int size=str.length();
407 if ( str[ size-1 ]==13 )
412 InterpretLine(str, insideComment);
419 catch (QuitException e)
423 catch (bbtk::Exception e)
425 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
426 if (mFileName.size())
428 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
429 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
433 catch (std::exception& e)
435 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
436 if (mFileName.size())
438 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
439 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
446 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
447 if (mFileName.size())
449 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
450 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
456 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
457 bbtkDecTab("Interpreter",9);
462 //=======================================================================
464 //=======================================================================
465 /// Runs the interpretation of a command
466 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
468 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
470 ExitStatus status = OK;
474 bool insideComment = false;
475 InterpretLine(line, insideComment);
477 catch (QuitException e)
481 catch (bbtk::Exception e)
483 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
486 catch (std::exception& e)
488 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
494 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
499 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
501 bbtkDecTab("Interpreter",9);
507 //=======================================================================
511 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
513 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
514 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
516 std::vector<std::string> words;
517 SplitLine(line,words);
522 bbtkDebugDecTab("Interpreter",9);
526 // Single line comment : # or //
527 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
529 bbtkDebugDecTab("Interpreter",9);
530 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
534 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
536 if (words[0][0]=='/' && words[0][1]=='*')
538 bbtkDebugDecTab("Interpreter",9);
539 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
540 insideComment = true;
544 if (words[0][0]=='*' && words[0][1]=='/')
546 bbtkDebugDecTab("Interpreter",9);
547 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
548 if ( !insideComment ) {
549 bbtkDebugDecTab("Interpreter",9);
550 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
552 insideComment = false;
558 bbtkDebugDecTab("Interpreter",9);
559 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
564 CommandInfoType command;
565 InterpretCommand(words,command);
567 bbtkDebugMessage("Interpreter",9,
568 "Command='"<<command.category
569 <<"' code="<<command.code<<std::endl);
571 std::string left,right,left2,right2;
572 std::string filename;
573 switch (command.code)
576 mExecuter->Create(words[1],words[2]);
581 // mExecuter->Remove(words[1]);
585 Utilities::SplitAroundFirstDot(words[1],left,right);
586 Utilities::SplitAroundFirstDot(words[2],left2,right2);
587 mExecuter->Connect(left,right,left2,right2);
591 mExecuter->BeginPackage(words[1]);
595 mExecuter->EndPackage();
599 if (mFileName.size()>0)
601 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
605 mExecuter->Define(words[1],"",filename);
609 mExecuter->Define(words[1],words[2],filename);
614 mExecuter->EndDefine();
618 Print(words[1]); /// \todo use generate command
622 if (words[1]=="freeze")
623 mExecuter->SetNoExecMode(true);
624 else if (words[1]=="unfreeze")
625 mExecuter->SetNoExecMode(false);
627 mExecuter->Update(words[1]);
631 Utilities::SplitAroundFirstDot(words[2],left,right);
632 mExecuter->DefineInput(words[1],left,right,words[3]);
636 Utilities::SplitAroundFirstDot(words[2],left,right);
637 mExecuter->DefineOutput(words[1],left,right,words[3]);
641 Utilities::SplitAroundFirstDot(words[1],left,right);
642 mExecuter->Set(left,right,words[2]);
646 mExecuter->Author(words[1]);
650 mExecuter->Category(words[1]);
655 Index("tmp_index.html");
656 else if (words.size()==2)
658 else if (words.size()==3)
659 Index(words[1],words[2]);
663 mExecuter->Description(words[1]);
673 bbtk::MessageManager::PrintInfo();
677 sscanf(words[2].c_str(),"%d",&level);
678 bbtk::MessageManager::SetMessageLevel(words[1],level);
691 this->mExecuter->Reset();
697 InterpretFile(words[1]);
701 SwitchToFile(words[1]);
703 // if 'source' was given
706 GetExecuter()->SetCurrentFileName(words[1]);
711 GetExecuter()->GetFactory()->LoadPackage(words[1]);
715 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
720 throw QuitException();
724 if (words.size() == 2)
726 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
727 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
731 mExecuter->SetWorkspaceName(words[2]);
736 bbtkInternalError("should not reach here !!!");
739 bbtkDecTab("Interpreter",9);
741 //=======================================================================
747 //=======================================================================
751 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
753 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
755 std::string delimiters = "\"";
756 std::vector<std::string> quote;
757 Utilities::SplitString(str,delimiters,quote);
760 std::vector<std::string>::iterator i;
761 for (i=quote.begin(); i!=quote.end(); )
763 Utilities::SplitString(*i,delimiters,tokens);
767 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
768 tokens.push_back(*i);
773 for (i=tokens.begin(); i!=tokens.end(); ++i)
775 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
777 bbtkDebugMessageCont("Interpreter",9,std::endl);
779 bbtkDebugDecTab("Interpreter",9);
781 //=======================================================================
784 //=======================================================================
785 // Replaces substrings "\\n" by a real carriage return "\n"
786 void SubsBackslashN ( std::string& s )
788 std::string ss("\\n");
789 std::string::size_type pos = 0;
792 while ( pos != std::string::npos )
794 s.replace(pos,2,cr,1);
795 pos = s.find(ss, pos-1);
798 //=======================================================================
801 //=======================================================================
805 void Interpreter::Print( const std::string& str)
807 if (mExecuter->GetNoExecMode()) return;
809 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
812 // InterpretLine ("load std")
813 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
814 // InterpretLine("new Print _P_")
815 // InterpretLine("connect _C_.Out _P_.In")
819 std::vector<std::string> chains;
820 std::string delimiters("$");
822 // Skip delimiters at beginning.
823 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
825 if (lastPos>0) is_text = false;
827 // Find first delimiter.
828 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
830 while (std::string::npos != pos || std::string::npos != lastPos)
834 // Found a text token, add it to the vector.
835 chains.push_back(str.substr(lastPos, pos - lastPos));
836 // std::string token = str.substr(lastPos, pos - lastPos)
837 // InterpretLine("set _C_.In%num% %token%")
843 // is an output (between $$) : decode
844 std::string tok,box,output;
845 tok = str.substr(lastPos, pos - lastPos);
846 Utilities::SplitAroundFirstDot(tok,box,output);
847 chains.push_back( mExecuter->Get(box,output) );
849 // InterpretLine("connect %tok% _C_.In%num%")
852 // Skip delimiters. Note the "not_of"
853 lastPos = str.find_first_not_of(delimiters, pos);
854 // Find next delimiter
855 pos = str.find_first_of(delimiters, lastPos);
860 // InterpretLine("exec _P_")
861 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
863 std::vector<std::string>::iterator i;
864 for (i= chains.begin(); i!=chains.end(); ++i)
866 // bbtkMessage("Echo",1,*i);
870 std::cout << std::endl;
871 bbtkDebugDecTab("Interpreter",9);
874 //=======================================================================
879 // ===================================================================================
881 void Interpreter::SwitchToFile( const std::string& name )
883 // Note : in the following :
884 // name : the user supplied name
885 // - abreviated name e.g. scr scr.bbs
886 // - relative full name e.g. ./scr.bbs ../../scr.bbs
887 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
888 // same for Windows, with c:, d: ...
890 // use ./directory/subdir/scrname.bbs
893 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
894 <<name<<"\")"<<std::endl);
896 std::vector<std::string> script_paths;
897 std::string fullPathScriptName; // full path script name
898 std::string pkgname; // e.g. <scriptname>.bbs
899 std::vector<std::string> Filenames;
901 // The following is *NOT* a debug time message :
902 // It's a user intended message.
903 // Please don't remove it.
904 bbtkMessage("Interpreter",1,
905 "look for : [" << name
906 << "]" << std::endl);
907 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
910 pkgname = Utilities::ExtractScriptName(name,upath);
912 bbtkMessage("Interpreter",1,
913 "extract : pkgname [" << pkgname
914 << "] upath [" << upath << "]" << std::endl);
915 bool fullnameGiven = false;
916 bool foundFile = false;
918 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
920 // std::cout << "JPR================== * found, load all boxes " << std::endl;
923 std::stringstream* stream = new std::stringstream;
924 //if (upath.size()!=0) // avoid troubles for "*"
926 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
928 // std::cout << "JPR================== absolute name, load all .bbs files " << std::endl;
929 int nbFiles = Utilities::Explore(upath, false, Filenames);
931 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
933 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
934 int lgr = (*i).size();
936 continue; // ignore non .bbs file
937 if ((*i).substr(lgr-4, 4) != ".bbs")
940 if (lgr > 10) // 10 -> '-appli.bbs'
942 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
943 continue; // ignore '-appli.bbs' files
947 (*stream) << "include " << *i << "\n";
948 //EED InterpretFile(*i);
953 bbtkMessage("Interpreter",2,
954 "WARNING : No '.bbs' file found in ["
955 << upath << "]" << std::endl);
957 SwitchToStream(stream);
963 std::vector<std::string>::iterator i;
964 std::string fullDirectoryName;
965 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
969 // we *really* want '.' to be the current working directory
971 char buf[2048]; // for getcwd
972 char * currentDir = getcwd(buf, 2048);
973 std::string cwd(currentDir);
977 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
979 // without last slash "\"
980 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
982 // Check if library exists
983 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
985 // The following is *NOT* a debug time message :
986 // It's a user intended message.
987 // Please don't remove it.
988 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
989 <<"] : doesn't exist" <<std::endl);
990 continue; // try next path
995 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
998 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1000 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
1001 int lgr = (*i).size();
1003 continue; // ignore non .bbs file
1004 if ((*i).substr(lgr-4, 4) != ".bbs")
1007 if (lgr > 10) // 10 -> '-appli.bbs'
1009 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
1010 continue; // ignore '-appli.bbs' files
1014 (*stream) << "include " << *i << "\n";
1015 //EED InterpretFile(*i);
1020 bbtkMessage("Interpreter",1,
1021 "WARNING : No '.bbs' file found in ["
1022 << fullDirectoryName << "]" << std::endl);
1024 SwitchToStream(stream);
1027 //break; // a directory was found; we stop iterating
1028 // LG : No! We want all files included !
1033 //std::string::size_type slash_position = name.find_last_of("/\\");
1035 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1036 // (not only a plain script name)
1037 // we trust him, and try to expland the directory name
1038 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1040 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1043 // ===========================================================check user supplied location
1044 fullnameGiven = true;
1046 fullPathScriptName = Utilities::ExpandLibName(name, false);
1048 // allow user to always forget ".bbs"
1049 int l = fullPathScriptName.size();
1055 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1057 fullPathScriptName = fullPathScriptName + ".bbs";
1062 fullPathScriptName = fullPathScriptName + ".bbs";
1065 if ( Utilities::FileExists(fullPathScriptName))
1072 // =============================================================== iterate on the paths
1075 std::vector<std::string>::iterator i;
1076 for (i=script_paths.begin();i!=script_paths.end();++i)
1079 // we *really* want '.' to be the current working directory
1081 char buf[2048]; // for getcwd
1082 char * currentDir = getcwd(buf, 2048);
1083 std::string cwd(currentDir);
1087 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1089 // Check if library exists
1090 if ( ! Utilities::FileExists(fullPathScriptName) )
1092 // The following is *NOT* a debug time message :
1093 // It's a user intended message.
1094 // Please don't remove it.
1095 bbtkMessage("Interpreter",2,
1096 " [" <<fullPathScriptName <<"] : doesn't exist"
1098 continue; // try next path
1100 bbtkMessage("Interpreter",2,
1101 " [" <<fullPathScriptName
1102 <<"] : found" <<std::endl);
1104 break; // a script was found; we stop iterating
1106 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1112 if(fullPathScriptName == "")
1113 bbtkError("Path ["<<upath<<"] doesn't exist");
1115 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1117 bbtkError("No ["<<pkgname<<".bbs] script found");
1121 LoadScript(fullPathScriptName,name);
1127 void Interpreter::SwitchToStream( std::stringstream* stream )
1129 //std::cout << "== 1 Entry in Interpreter::SwitchToStream " << std::endl;
1131 mFile.push_back(stream);
1132 //std::cout << " mFile.size() " << mFile.size() << std::endl;
1133 std::ostringstream buffer_name;
1135 buffer_name << "buffer_" ; // << bufferNb;
1137 // std::cout << " mFile.size() " << mFile.size() << std::endl;
1138 // std::cout << " mFileName.size() " << mFileName.size() << std::endl;
1139 // std::cout << " mLine.size() " << mLine.size() << std::endl;
1140 // std::vector<std::string>::iterator j = mFileName.begin();
1141 // std::cout << " mFileName.begin() succeeded" << std::endl;
1142 // std::cout << " mFileName[0] " << mFileName[0] << std::endl;
1143 //std::cout << " mFileName.begin() " << mFileName.begin() << std::endl;
1145 for( std::vector<std::string>::iterator i = mFileName.begin(); i!= mFileName.end(); ++i)
1148 std::cout << "Interpreter::SwitchToStream : mFileName [" << *i << "]" << std::endl;
1151 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1152 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1154 if (mFileName.size()>0 )// && (mFile.size()>0) ) // NO!!!
1156 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1157 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1158 buffer_name << mFileName.back() << "_" << mLine.back();
1160 //std::cout << "3 in Interpreter::SwitchToStream buffer_name :[" << buffer_name.str() << "]" << std::endl;
1161 mFileName.push_back(buffer_name.str());
1162 mIncludeFileName.push_back(buffer_name.str());
1166 //=======================================================================
1168 void Interpreter::LoadScript( std::string fullPathScriptName,
1169 std::string includeScriptName)
1171 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1173 bool okScriptExist=false;
1174 int iStrScript,sizeVecStricpt=mFileName.size();
1175 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1177 if (mFileName[iStrScript] == fullPathScriptName )
1183 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1184 // if (okScriptExist==true)
1186 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1187 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1192 s = new std::ifstream;
1193 s->open(fullPathScriptName.c_str());
1196 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1200 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1201 << "] found" << std::endl);
1204 mFileName.push_back(fullPathScriptName);
1205 mIncludeFileName.push_back(includeScriptName);
1210 //=======================================================================
1214 void Interpreter::CloseCurrentFile()
1216 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1219 if (mFile.size()==0)
1221 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1225 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1227 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1228 if (file!=0) file->close();
1230 delete mFile.back();
1232 mFileName.pop_back();
1233 mIncludeFileName.pop_back();
1236 bbtkDebugMessage("Interpreter",9," Remains "
1238 <<" open"<<std::endl);
1239 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1242 //=======================================================================
1244 //=======================================================================
1248 void Interpreter::CloseAllFiles()
1250 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1253 while (mFile.size() != 0)
1257 mFile.back()->close();
1258 delete mFile.back();
1260 bbtkDebugMessage("Interpreter",9,
1261 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1262 mFileName.pop_back();
1263 mIncludeFileName.pop_back();
1267 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1270 //=======================================================================
1274 //=======================================================================
1278 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1279 CommandInfoType& info )
1281 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1283 // searches the command category
1284 CommandDictType::iterator c;
1285 c = mCommandDict.find(words[0]);
1286 if ( c == mCommandDict.end() ) {
1287 bbtkError(words[0]<<" : unknown command");
1290 // tests the number of args
1291 if ( ( words.size()-1 < c->second.argmin ) ||
1292 ( words.size()-1 > c->second.argmax ) )
1294 HelpCommand(words[0]);
1295 bbtkError(words[0]<<" : wrong number of arguments");
1299 bbtkDecTab("Interpreter",9);
1301 //=======================================================================
1304 //=======================================================================
1305 /// Displays help on all the commands
1306 void Interpreter::Help(const std::vector<std::string>& words)
1308 unsigned int nbarg = words.size()-1;
1316 if (words[1]=="packages")
1318 GetExecuter()->GetFactory()->PrintPackages(true);
1323 HelpCommand(words[1]);
1325 catch (bbtk::Exception e)
1329 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1330 #ifdef _USE_WXWIDGETS_
1331 if ( mWxConsole != 0 )
1334 ConfigurationFile::GetInstance().Get_doc_path();
1335 url += "/bbdoc/" + words[1] + "/index.html";
1336 if (Utilities::FileExists(url))
1338 mWxConsole->ShowHtmlPage(url);
1343 catch (bbtk::Exception f)
1347 std::string package;
1348 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1349 #ifdef _USE_WXWIDGETS_
1350 if ( mWxConsole != 0 )
1353 ConfigurationFile::GetInstance().Get_doc_path();
1354 url += "/bbdoc/" + package + "/index.html";
1355 if (Utilities::FileExists(url))
1357 url += "#" + words[1];
1358 mWxConsole->ShowHtmlPage(url);
1363 catch (bbtk::Exception g)
1367 GetExecuter()->ShowRelations(words[1],"0","9999");
1369 catch (bbtk::Exception h){
1370 bbtkError("\""<<words[1].c_str()
1371 <<"\" is not a known command, package, black box type or black box name");
1379 if (words[2]=="all")
1381 if ( words[1]=="packages" )
1383 GetExecuter()->GetFactory()->PrintPackages(true,true);
1388 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1390 catch (bbtk::Exception f)
1396 HelpCommand(words[0]);
1397 bbtkError(words[0]<<" : syntax error");
1402 bbtkError("Should not reach here !!!");
1405 //=======================================================================
1407 //===================================================================
1408 /// Displays the Configuration
1409 void Interpreter::Config() const
1411 ConfigurationFile::GetInstance().GetHelp(1);
1413 //===================================================================
1415 //=======================================================================
1416 /// Displays help on all the commands
1417 void Interpreter::HelpCommands()
1419 std::cout << "Available commands :" << std::endl;
1420 CommandDictType::iterator i;
1421 for ( i = mCommandDict.begin();
1422 i != mCommandDict.end();
1424 std::cout << " " << i->first << std::endl;
1425 // std::cout << " usage : " << i->second.syntax << std::endl;
1426 // std::cout << " " << i->second.help << std::endl;
1430 //=======================================================================
1433 //=======================================================================
1434 /// Displays help on a particular commands
1435 void Interpreter::HelpCommand(const std::string& s)
1437 CommandDictType::iterator c;
1438 c = mCommandDict.find(s);
1439 if ( c == mCommandDict.end() ) {
1440 bbtkError(s<<" : Unknown command");
1442 // std::cout << " " << s << " : "<< std::endl;
1443 // CommandParamDictType::iterator i;
1444 // for ( i = c->second.begin();
1445 // i != c->second.end();
1447 std::cout << " usage : " << c->second.syntax << std::endl;
1448 std::cout << " " << c->second.help << std::endl;
1451 //=======================================================================
1454 //=======================================================================
1455 /// Fills the vector commands with the commands which
1456 /// have the first n chars of buf for prefix
1457 /// TODO : skip initial spaces in buf and also return the position of first
1458 /// non blank char in buf
1459 void Interpreter::FindCommandsWithPrefix( char* buf,
1461 std::vector<std::string>& commands )
1463 CommandDictType::const_iterator i;
1464 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1466 if ((i->first).find(buf,0,n) == 0)
1467 commands.push_back(i->first);
1470 //=======================================================================
1474 //=======================================================================
1475 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1477 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1478 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1480 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1481 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1482 // E.G. STORE THIS IN bbtk_config.xml
1483 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1484 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1485 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1486 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1487 #define BBTK_BACKSPACE_KBCODE 0x00000008
1488 #define BBTK_DEL_KBCODE 0x0000007F
1489 #define BBTK_SPACE_KBCODE 0x00000020
1491 //=======================================================================
1492 void Interpreter::GetLineFromPrompt(std::string& s)
1497 int MAX_LINE_SIZE = 160;
1498 int MAX_HISTORY_SIZE = 100;
1500 char* newline = new char[MAX_LINE_SIZE];
1501 memset(newline,0,MAX_LINE_SIZE);
1502 char* histline = new char[MAX_LINE_SIZE];
1503 memset(histline,0,MAX_LINE_SIZE);
1505 char* line = newline;
1506 int hist = mHistory.size();
1512 read ( STDIN_FILENO, &c, 4) ;
1514 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1516 // Printable character
1517 if ( (ind<MAX_LINE_SIZE-1) &&
1518 ( c >= BBTK_SPACE_KBCODE ) &&
1519 ( c < BBTK_DEL_KBCODE ))
1527 // delete the unused line
1533 // empty lines are not stored in from history
1536 // if history too long : delete oldest command
1537 if (mHistory.size()>MAX_HISTORY_SIZE)
1539 delete mHistory.front();
1540 mHistory.pop_front();
1542 mHistory.push_back(line);
1547 else if ( (ind>0) &&
1548 ((c == BBTK_BACKSPACE_KBCODE) ||
1549 (c == BBTK_DEL_KBCODE)) )
1557 // TODO : Command completion
1558 std::vector<std::string> commands;
1559 FindCommandsWithPrefix( line,ind,commands);
1560 if (commands.size()==1)
1562 std::string com = *commands.begin();
1563 for (; ind<com.size(); ++ind)
1565 PrintChar(com[ind]);
1571 else if (commands.size()>1)
1573 std::vector<std::string>::iterator i;
1575 for (i=commands.begin();i!=commands.end();++i)
1577 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1580 write(STDOUT_FILENO,"\n> ",3);
1581 //for (int j=0;j<ind;++j)
1583 write(STDOUT_FILENO,line,ind);
1587 // Arrow up : back in history
1588 else if (c==BBTK_UP_ARROW_KBCODE)
1592 // erase current line
1593 while (ind--) BackSpace();
1597 strcpy(histline,mHistory[hist]);
1601 write(STDOUT_FILENO,line,ind);
1604 // Arrow down : down in history
1605 else if (c==BBTK_DOWN_ARROW_KBCODE)
1607 if (hist<mHistory.size()-1)
1609 // erase current line
1610 while (ind--) BackSpace();
1614 strcpy(histline,mHistory[hist]);
1618 write(STDOUT_FILENO,line,ind);
1620 // end of history : switch back to newline
1621 else if (hist==mHistory.size()-1)
1623 // erase current line
1624 while (ind--) BackSpace();
1631 write(STDOUT_FILENO,line,ind);
1635 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1637 PrintChar(line[ind]);
1642 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1650 write(STDOUT_FILENO,"\n\r",2);
1658 //=======================================================================
1659 void Interpreter::GetLineFromPrompt(std::string& s)
1685 //=======================================================================
1691 //=======================================================================
1692 void Interpreter::CommandLineInterpreter()
1694 bbtkDebugMessageInc("Interpreter",9,
1695 "Interpreter::CommandLineInterpreter()"<<std::endl);
1697 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1698 // Initialise the tty in non canonical mode with no echo
1699 // oter remembers the previous settings to restore them after
1700 struct termios ter,oter;
1703 ter.c_lflag &= ~ECHO;
1704 ter.c_lflag &= ~ICANON;
1707 tcsetattr(0,TCSANOW,&ter);
1710 mCommandLine = true;
1712 bool insideComment = false; // for multiline comment
1718 GetLineFromPrompt(line);
1719 InterpretLine(line, insideComment);
1721 catch (QuitException e)
1723 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1726 catch (bbtk::Exception e)
1730 catch (std::exception& e)
1732 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1736 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1741 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1742 tcsetattr(0,TCSANOW,&oter);
1745 std::cout << "Good bye !" << std::endl;
1747 bbtkDebugDecTab("Interpreter",9);
1750 //=======================================================================
1751 void Interpreter::Graph(const std::vector<std::string>& words)
1754 bool system_display = true;
1756 #ifdef _USE_WXWIDGETS_
1757 if ( mWxConsole != 0 ) system_display = false;
1760 if (words.size()==1)
1762 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1764 else if (words.size()==2)
1766 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1768 else if (words.size()==3)
1770 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1772 else if (words.size()==4)
1774 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1776 else if (words.size()==5)
1778 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1780 else if (words.size()==6)
1782 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1784 else if (words.size()==7)
1786 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1789 #ifdef _USE_WXWIDGETS_
1790 if ( mWxConsole != 0 )
1791 mWxConsole->ShowHtmlPage(page);
1794 //=======================================================================
1797 //=======================================================================
1798 void Interpreter::Index(const std::string& filename,
1799 const std::string& type)
1801 Factory::IndexEntryType t;
1802 if (type=="Initials") t = Factory::Initials;
1803 else if (type=="Categories") t = Factory::Categories;
1804 else if (type=="Packages") t = Factory::Packages;
1805 else if (type=="Adaptors") t = Factory::Adaptors;
1807 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1809 //=======================================================================