1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/26 08:27:19 $
7 Version: $Revision: 1.55 $
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 "bbtkUtilities.h"
29 #ifdef CMAKE_HAVE_TERMIOS_H
31 #define BBTK_USE_TERMIOS_BASED_PROMPT
39 //Interpreter* Interpreter::mGlobalInterpreter = NULL;
41 //=======================================================================
45 Interpreter::Interpreter()
52 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
53 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
54 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
56 mExecuter = new bbtk::Executer();
57 mExecuter->SetInterpreter(this);
59 // For the time being, comment out previous line, and
60 // uncomment next line to check Transcriptor
62 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
64 // Builds the commands dict
67 info.category = "new";
71 info.syntax = "new <type> <name>";
72 info.help = "Creates a new black box of type <type> with name <name>";
73 mCommandDict[info.category] = info;
75 info.category = "delete";
79 info.syntax = "delete <box>";
80 info.help = "Deletes the black box of name <box>";
81 mCommandDict[info.category] = info;
83 info.category = "connect";
87 info.syntax = "connect <box1.output> <box2.input>";
88 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
89 mCommandDict[info.category] = info;
91 info.category = "print";
95 info.syntax = "print <string>";
96 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').";
97 mCommandDict[info.category] = info;
99 info.category = "exec";
103 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
104 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.";
105 mCommandDict[info.category] = info;
107 info.category = "package";
110 info.code = cPackage;
111 info.syntax = "package <name>";
112 info.help = "Begins the definition of a package.";
113 mCommandDict[info.category] = info;
115 info.category = "endpackage";
118 info.code = cEndPackage;
119 info.syntax = "endpackage";
120 info.help = "Ends the definition of a package.";
121 mCommandDict[info.category] = info;
123 info.category = "define";
127 info.syntax = "define <type> [<package>]";
128 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.";
129 mCommandDict[info.category] = info;
131 info.category = "endefine";
134 info.code = cEndDefine;
135 info.syntax = "endefine";
136 info.help = "Ends the definition of a new type of complex black box";
137 mCommandDict[info.category] = info;
139 info.category = "input";
143 info.syntax = "input <name> <box.input> <help>";
144 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";
145 mCommandDict[info.category] = info;
147 info.category = "output";
151 info.syntax = "output <name> <box.output> <help>";
152 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";
153 mCommandDict[info.category] = info;
155 info.category = "set";
159 info.syntax = "set <box.input> <value>";
160 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";
161 mCommandDict[info.category] = info;
163 info.category = "config"; // JPR
167 info.syntax = "config";
168 info.help = "Prints the value of all configuration parameters";
169 mCommandDict[info.category] = info;
171 info.category = "index"; // LG
176 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
177 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.";
178 mCommandDict[info.category] = info;
180 info.category = "reset";
184 info.syntax = "reset";
185 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
186 mCommandDict[info.category] = info;
188 info.category = "author";
192 info.syntax = "author <string>";
193 info.help = "Adds the string <string> to the author information of the black box being defined";
194 mCommandDict[info.category] = info;
196 info.category = "category"; //JP
199 info.code = cCategory;
200 info.syntax = "category <list of items, separated by ;>";
201 info.help = "Adds the string <string> to the category information of the black box being defined";
202 mCommandDict[info.category] = info;
204 info.category = "description";
207 info.code = cDescription;
208 info.syntax = "description <string>";
209 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
210 mCommandDict[info.category] = info;
212 info.category = "help";
216 info.syntax = "help";
217 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>";
218 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.";
219 mCommandDict[info.category] = info;
221 info.category = "message";
224 info.code = cMessage;
225 info.syntax = "message <kind> <level>";
226 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;
228 info.category = "include";
231 info.code = cInclude;
232 info.syntax = "include <filename> [source]";
233 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).";
234 mCommandDict[info.category] = info;
236 info.category = "quit";
240 info.syntax = "quit";
241 info.help = "Quits the program (during script execution it stops the complete execution)";
242 mCommandDict[info.category] = info;
244 info.category = "load";
248 info.syntax = "load <packagename>";
249 info.help = "Loads the black box package <packagename>";
250 mCommandDict[info.category] = info;
252 info.category = "unload";
256 info.syntax = "unload <packagename>";
257 info.help = "Unloads the black box package <packagename>";
258 mCommandDict[info.category] = info;
260 info.category = "graph";
264 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 ]]]]]]";
265 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')";
266 mCommandDict[info.category] = info;
269 info.category = "workspace";
272 info.code = cWorkspace;
273 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
274 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.";
275 mCommandDict[info.category] = info;
278 bbtkDebugDecTab("Interpreter",9);
281 //=======================================================================
285 //=======================================================================
289 Interpreter::~Interpreter()
291 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
294 bbtkDebugDecTab("Interpreter",9);
296 //=======================================================================
299 InterpreterError::InterpreterError( const std::string& message,
301 const std::string& script_file,
304 : Exception("Interpreter",0,message),
305 mInScriptFile(in_script_file),
306 mScriptFile(script_file),
307 mScriptLine(script_line)
310 InterpreterError::InterpreterError( const Exception& excep,
312 const std::string& script_file,
316 mInScriptFile(in_script_file),
317 mScriptFile(script_file),
318 mScriptLine(script_line)
321 //=======================================================================
322 void Interpreter::CatchBbtkException( const bbtk::Exception& e )
326 bool in_script = false;
327 std::string file("");
329 if (mFileName.size()) {
330 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
331 if (fs!=0) in_script = true;
332 file = mFileName.back();
336 throw InterpreterError(e,in_script,file,line);
340 std::stringstream mess;
341 mess << "* ERROR : "<<e.GetMessage()<<std::endl;
342 if (mFileName.size()) {
343 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
344 mess << "* LINE : "<<mLine.back()<<std::endl;
346 std::cerr << mess.str();
349 //=======================================================================
351 //=======================================================================
352 void Interpreter::CatchStdException( const std::exception& e )
356 bool in_script = false;
357 std::string file("");
359 if (mFileName.size()) {
360 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
361 if (fs!=0) in_script = true;
362 file = mFileName.back();
366 throw InterpreterError(e.what(),in_script,file,line);
370 std::stringstream mess;
371 mess << "* ERROR : "<<e.what()<<std::endl;
372 if (mFileName.size()) {
373 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
374 mess << "* LINE : "<<mLine.back()<<std::endl;
376 std::cerr << mess.str();
379 //=======================================================================
381 //=======================================================================
382 void Interpreter::CatchUnknownException()
386 bool in_script = false;
387 std::string file("");
389 if (mFileName.size()) {
390 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
391 if (fs!=0) in_script = true;
392 file = mFileName.back();
396 throw InterpreterError("Unknown exception caught",
397 in_script,file,line);
401 std::stringstream mess;
402 mess << "* UNDEFINED ERROR (not a bbtk nor a std exception)"
404 if (mFileName.size()) {
405 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
406 mess << "* LINE : "<<mLine.back()<<std::endl;
408 std::cerr << mess.str();
411 //=======================================================================
413 //=======================================================================
415 #define CATCH_MACRO \
416 catch (QuitException e) \
418 status = Interpreter_QUIT; \
419 if (mThrow) throw QuitException(); \
421 catch (bbtk::Exception e) \
423 status = Interpreter_ERROR; \
424 CatchBbtkException(e); \
426 catch (std::exception& e) \
428 status = Interpreter_ERROR; \
429 CatchStdException(e); \
433 status = Interpreter_ERROR; \
434 CatchUnknownException(); \
436 //=======================================================================
439 //=======================================================================
443 Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
445 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
447 bool exm = mCommandLine;
448 mCommandLine = false;
450 ExitStatus status = Interpreter_OK;
454 SwitchToFile(filename);
456 bool insideComment = false; // for multiline comment
457 while (mFile.size()>0)
459 while (!mFile.back()->eof()) {
462 mFile.back()->getline(buf,500);
463 std::string str(buf);
464 int size=str.length();
465 if ( str[ size-1 ]==13 )
470 InterpretLine(str, insideComment);
479 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
480 bbtkDecTab("Interpreter",9);
486 //=======================================================================
489 //=======================================================================
493 Interpreter::ExitStatus
494 Interpreter::InterpretBuffer( std::stringstream* buffer )
496 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
498 bool exm = mCommandLine;
499 mCommandLine = false;
501 ExitStatus status = Interpreter_OK;
505 SwitchToStream(buffer);
506 bool insideComment = false; // for multiline comment
507 while (mFile.size()>0)
509 while (!mFile.back()->eof()) {
512 mFile.back()->getline(buf,500);
513 std::string str(buf);
515 int size=str.length();
516 if ( str[ size-1 ]==13 )
521 InterpretLine(str, insideComment);
531 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
532 bbtkDecTab("Interpreter",9);
537 //=======================================================================
539 //=======================================================================
540 /// Runs the interpretation of a command
541 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
543 printf("EED Interpreter::InterpretLine %s \n", line.c_str() );
544 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
546 ExitStatus status = Interpreter_OK;
550 bool insideComment = false;
551 InterpretLine(line, insideComment);
555 catch (QuitException e)
557 status = Interpreter_QUIT;
559 catch (bbtk::Exception e)
561 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
562 status = Interpreter_ERROR;
564 catch (std::exception& e)
566 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
567 status = Interpreter_ERROR;
572 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
573 status = Interpreter_ERROR;
577 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
579 bbtkDecTab("Interpreter",9);
585 //=======================================================================
589 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
591 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
592 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
594 std::vector<std::string> words;
595 SplitLine(line,words);
600 bbtkDebugDecTab("Interpreter",9);
604 // Single line comment : # or //
605 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
607 bbtkDebugDecTab("Interpreter",9);
608 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
612 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
614 if (words[0][0]=='/' && words[0][1]=='*')
616 bbtkDebugDecTab("Interpreter",9);
617 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
618 insideComment = true;
622 if (words[0][0]=='*' && words[0][1]=='/')
624 bbtkDebugDecTab("Interpreter",9);
625 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
626 if ( !insideComment ) {
627 bbtkDebugDecTab("Interpreter",9);
628 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
630 insideComment = false;
636 bbtkDebugDecTab("Interpreter",9);
637 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
642 CommandInfoType command;
643 InterpretCommand(words,command);
645 bbtkDebugMessage("Interpreter",9,
646 "Command='"<<command.category
647 <<"' code="<<command.code<<std::endl);
649 std::string left,right,left2,right2;
650 std::string filename;
651 switch (command.code)
654 mExecuter->Create(words[1],words[2]);
658 mExecuter->Destroy(words[1]);
662 Utilities::SplitAroundFirstDot(words[1],left,right);
663 Utilities::SplitAroundFirstDot(words[2],left2,right2);
664 mExecuter->Connect(left,right,left2,right2);
668 mExecuter->BeginPackage(words[1]);
672 mExecuter->EndPackage();
676 if (mFileName.size()>0)
678 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
682 mExecuter->Define(words[1],"",filename);
686 mExecuter->Define(words[1],words[2],filename);
691 mExecuter->EndDefine();
695 mExecuter->Print(words[1]);
699 if (words[1]=="freeze")
700 mExecuter->SetNoExecMode(true);
701 else if (words[1]=="unfreeze")
702 mExecuter->SetNoExecMode(false);
704 mExecuter->Execute(words[1]);
708 Utilities::SplitAroundFirstDot(words[2],left,right);
709 mExecuter->DefineInput(words[1],left,right,words[3]);
713 Utilities::SplitAroundFirstDot(words[2],left,right);
714 mExecuter->DefineOutput(words[1],left,right,words[3]);
718 Utilities::SplitAroundFirstDot(words[1],left,right);
719 mExecuter->Set(left,right,words[2]);
723 mExecuter->Author(words[1]);
727 mExecuter->Category(words[1]);
732 Index("tmp_index.html");
733 else if (words.size()==2)
735 else if (words.size()==3)
736 Index(words[1],words[2]);
740 mExecuter->Description(words[1]);
750 mExecuter->HelpMessages();
754 sscanf(words[2].c_str(),"%d",&level);
755 mExecuter->SetMessageLevel(words[1],level);
768 this->mExecuter->Reset();
774 InterpretFile(words[1]);
778 SwitchToFile(words[1]);
780 // if 'source' was given
783 GetExecuter()->SetCurrentFileName(words[1]);
788 GetExecuter()->LoadPackage(words[1]);
792 GetExecuter()->UnLoadPackage(words[1]);
797 throw QuitException();
801 if (words.size() == 2)
803 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
804 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
808 mExecuter->SetWorkspaceName(words[2]);
813 bbtkInternalError("should not reach here !!!");
816 bbtkDecTab("Interpreter",9);
818 //=======================================================================
824 //=======================================================================
828 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
830 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
832 std::string delimiters = "\"";
833 std::vector<std::string> quote;
834 Utilities::SplitString(str,delimiters,quote);
837 std::vector<std::string>::iterator i;
838 for (i=quote.begin(); i!=quote.end(); )
840 Utilities::SplitString(*i,delimiters,tokens);
844 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
845 tokens.push_back(*i);
850 for (i=tokens.begin(); i!=tokens.end(); ++i)
852 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
854 bbtkDebugMessageCont("Interpreter",9,std::endl);
856 bbtkDebugDecTab("Interpreter",9);
858 //=======================================================================
863 //=======================================================================
868 void Interpreter::Print( const std::string& str)
870 if (mExecuter->GetNoExecMode()) return;
872 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
875 // InterpretLine ("load std")
876 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
877 // InterpretLine("new Print _P_")
878 // InterpretLine("connect _C_.Out _P_.In")
882 std::vector<std::string> chains;
883 std::string delimiters("$");
885 // Skip delimiters at beginning.
886 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
888 if (lastPos>0) is_text = false;
890 // Find first delimiter.
891 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
893 while (std::string::npos != pos || std::string::npos != lastPos)
897 // Found a text token, add it to the vector.
898 chains.push_back(str.substr(lastPos, pos - lastPos));
899 // std::string token = str.substr(lastPos, pos - lastPos)
900 // InterpretLine("set _C_.In%num% %token%")
906 // is an output (between $$) : decode
907 std::string tok,box,output;
908 tok = str.substr(lastPos, pos - lastPos);
909 Utilities::SplitAroundFirstDot(tok,box,output);
910 chains.push_back( mExecuter->Get(box,output) );
912 // InterpretLine("connect %tok% _C_.In%num%")
915 // Skip delimiters. Note the "not_of"
916 lastPos = str.find_first_not_of(delimiters, pos);
917 // Find next delimiter
918 pos = str.find_first_of(delimiters, lastPos);
923 // InterpretLine("exec _P_")
924 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
926 std::vector<std::string>::iterator i;
927 for (i= chains.begin(); i!=chains.end(); ++i)
929 // bbtkMessage("Echo",1,*i);
930 Utilities::SubsBackslashN(*i);
933 std::cout << std::endl;
934 bbtkDebugDecTab("Interpreter",9);
938 //=======================================================================
943 // ===================================================================================
945 void Interpreter::SwitchToFile( const std::string& name )
947 // Note : in the following :
948 // name : the user supplied name
949 // - abreviated name e.g. scr scr.bbs
950 // - relative full name e.g. ./scr.bbs ../../scr.bbs
951 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
952 // same for Windows, with c:, d: ...
954 // use ./directory/subdir/scrname.bbs
957 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
958 <<name<<"\")"<<std::endl);
960 std::vector<std::string> script_paths;
961 std::string fullPathScriptName; // full path script name
962 std::string pkgname; // e.g. <scriptname>.bbs
963 std::vector<std::string> Filenames;
965 // The following is *NOT* a debug time message :
966 // It's a user intended message.
967 // Please don't remove it.
968 bbtkMessage("Interpreter",1,
969 "look for : [" << name
970 << "]" << std::endl);
974 pkgname = Utilities::ExtractScriptName(name,upath);
976 bbtkMessage("Interpreter",1,
977 "extract : pkgname [" << pkgname
978 << "] upath [" << upath << "]" << std::endl);
979 bool fullnameGiven = false;
980 bool foundFile = false;
982 // ==== "*" provided : load all scripts in given path
983 // relative (e.g. std/boxes/*) or absolute
988 std::stringstream* stream = new std::stringstream;
989 //if (upath.size()!=0) // avoid troubles for "*"
991 // ==== no path provided : look in root bbs path
994 // bbtkMessage("Interpreter",1,
995 script_paths.push_back( ConfigurationFile::GetInstance().Get_root_bbs_path() );
997 // ==== absolute path provided
998 else if (upath[0]=='/' || upath[1] == ':' )
1000 script_paths.push_back(upath);
1002 // ==== relative path provided : search all bbs path appended with
1003 // the relative path provided
1006 std::vector<std::string>::const_iterator i;
1007 for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1008 i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1011 std::string full_path(*i);
1012 full_path += ConfigurationFile::GetInstance().Get_file_separator();
1014 script_paths.push_back(full_path);
1017 // === search paths list complete : now explore it
1018 bbtkMessage("Interpreter",1,
1019 "'*' provided. search paths : " << std::endl);
1021 int nbFiles = Utilities::Explore(upath, false, Filenames);
1023 for (std::vector<std::string>::iterator i = Filenames.begin();
1024 i!= Filenames.end(); ++i)
1026 int lgr = (*i).size();
1028 continue; // ignore non .bbs file
1029 if ((*i).substr(lgr-4, 4) != ".bbs")
1031 //printf("EED Interpreter::SwitchToFile flag01 %s \n", (*i).c_str() );
1032 (*stream) << "include \"" << *i << "\"\n";
1038 bbtkMessage("Interpreter",2,
1039 "WARNING : No '.bbs' file found in ["
1040 << upath << "]" << std::endl);
1044 SwitchToStream(stream);
1050 std::vector<std::string>::iterator i;
1051 std::string fullDirectoryName;
1052 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1056 bbtkMessage("Interpreter",1,
1057 "----> '" << path << "'" << std::endl);
1058 // we *really* want '.' to be the current working directory
1060 char buf[2048]; // for getcwd
1061 char * currentDir = getcwd(buf, 2048);
1062 std::string cwd(currentDir);
1066 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
1068 // without last slash "\"
1069 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
1071 // Check if directory exists
1072 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
1074 // The following is *NOT* a debug time message :
1075 // It's a user intended message.
1076 // Please don't remove it.
1077 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
1078 <<"] : doesn't exist" <<std::endl);
1079 continue; // try next path
1084 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
1087 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1089 int lgr = (*i).size();
1091 continue; // ignore non .bbs file
1092 if ((*i).substr(lgr-4, 4) != ".bbs")
1095 // printf("EED Interpreter::SwitchToFile flag02 %s \n", (*i).c_str() );
1096 (*stream) << "include \"" << *i << "\"\n";
1102 bbtkMessage("Interpreter",1,
1103 "WARNING : No '.bbs' file found in ["
1104 << fullDirectoryName << "]" << std::endl);
1108 SwitchToStream(stream);
1111 //break; // a directory was found; we stop iterating
1112 // LG : No! We want all files included !
1116 //=============== end pkgname=="*" ===========
1119 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1120 // (not only a plain script name)
1121 // we trust him, and try to expland the directory name
1122 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1124 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1127 // ===========================================================check user supplied location
1128 fullnameGiven = true;
1130 fullPathScriptName = Utilities::ExpandLibName(name, false);
1132 // allow user to always forget ".bbs"
1133 int l = fullPathScriptName.size();
1139 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1141 fullPathScriptName = fullPathScriptName + ".bbs";
1146 fullPathScriptName = fullPathScriptName + ".bbs";
1149 if ( Utilities::FileExists(fullPathScriptName))
1156 // =============================== iterate on the paths
1158 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1160 std::vector<std::string>::iterator i;
1161 for (i=script_paths.begin();i!=script_paths.end();++i)
1164 // we *really* want '.' to be the current working directory
1166 char buf[2048]; // for getcwd
1167 char * currentDir = getcwd(buf, 2048);
1168 std::string cwd(currentDir);
1172 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1174 // Check if library exists
1175 if ( ! Utilities::FileExists(fullPathScriptName) )
1177 // The following is *NOT* a debug time message :
1178 // It's a user intended message.
1179 // Please don't remove it.
1180 bbtkMessage("Interpreter",2,
1181 " [" <<fullPathScriptName <<"] : doesn't exist"
1183 continue; // try next path
1185 bbtkMessage("Interpreter",2,
1186 " [" <<fullPathScriptName
1187 <<"] : found" <<std::endl);
1189 break; // a script was found; we stop iterating
1191 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1197 if(fullPathScriptName == "")
1198 bbtkError("Path ["<<upath<<"] doesn't exist");
1200 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1202 bbtkError("No ["<<pkgname<<".bbs] script found");
1206 LoadScript(fullPathScriptName,name);
1210 //=======================================================================
1213 //=======================================================================
1214 void Interpreter::SwitchToStream( std::stringstream* stream )
1216 mFile.push_back(stream);
1217 std::ostringstream buffer_name;
1219 buffer_name << "buffer_" ;
1221 if (mFileName.size()>0 )
1223 buffer_name << mFileName.back() << "_" << mLine.back();
1225 mFileName.push_back(buffer_name.str());
1226 mIncludeFileName.push_back(buffer_name.str());
1229 //=======================================================================
1231 //=======================================================================
1233 void Interpreter::LoadScript( std::string fullPathScriptName,
1234 std::string includeScriptName)
1236 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1238 bool okScriptExist=false;
1239 int iStrScript,sizeVecStricpt=mFileName.size();
1240 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1242 if (mFileName[iStrScript] == fullPathScriptName )
1248 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1249 // if (okScriptExist==true)
1251 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1252 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1257 s = new std::ifstream;
1258 s->open(fullPathScriptName.c_str());
1261 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1265 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1266 << "] found" << std::endl);
1269 mFileName.push_back(fullPathScriptName);
1270 mIncludeFileName.push_back(includeScriptName);
1276 //=======================================================================
1280 void Interpreter::CloseCurrentFile()
1282 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1285 if (mFile.size()==0)
1287 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1291 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1293 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1294 if (file!=0) file->close();
1296 delete mFile.back();
1298 mFileName.pop_back();
1299 mIncludeFileName.pop_back();
1302 bbtkDebugMessage("Interpreter",9," Remains "
1304 <<" open"<<std::endl);
1305 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1308 //=======================================================================
1310 //=======================================================================
1314 void Interpreter::CloseAllFiles()
1316 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1319 while (mFile.size() != 0)
1323 mFile.back()->close();
1324 delete mFile.back();
1326 bbtkDebugMessage("Interpreter",9,
1327 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1328 mFileName.pop_back();
1329 mIncludeFileName.pop_back();
1333 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1336 //=======================================================================
1340 //=======================================================================
1344 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1345 CommandInfoType& info )
1347 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1349 // searches the command category
1350 CommandDictType::iterator c;
1351 c = mCommandDict.find(words[0]);
1352 if ( c == mCommandDict.end() ) {
1353 bbtkError(words[0]<<" : unknown command");
1356 // tests the number of args
1357 if ( ( words.size()-1 < c->second.argmin ) ||
1358 ( words.size()-1 > c->second.argmax ) )
1360 HelpCommand(words[0]);
1361 bbtkError(words[0]<<" : wrong number of arguments");
1365 bbtkDecTab("Interpreter",9);
1367 //=======================================================================
1370 //=======================================================================
1371 /// Displays help on all the commands
1372 void Interpreter::Help(const std::vector<std::string>& words)
1374 unsigned int nbarg = words.size()-1;
1382 if (words[1]=="packages")
1384 GetExecuter()->GetFactory()->PrintPackages(true);
1389 HelpCommand(words[1]);
1391 catch (bbtk::Exception e)
1395 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1399 ConfigurationFile::GetInstance().Get_doc_path();
1400 url += "/bbdoc/" + words[1] + "/index.html";
1401 if (Utilities::FileExists(url))
1403 mUser->InterpreterUserViewHtmlPage(url);
1407 catch (bbtk::Exception f)
1411 std::string package;
1412 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1416 ConfigurationFile::GetInstance().Get_doc_path();
1417 url += "/bbdoc/" + package + "/index.html";
1418 if (Utilities::FileExists(url))
1420 url += "#" + words[1];
1421 mUser->InterpreterUserViewHtmlPage(url);
1425 catch (bbtk::Exception g)
1429 GetExecuter()->ShowRelations(words[1],"0","9999");
1431 catch (bbtk::Exception h){
1432 bbtkError("\""<<words[1].c_str()
1433 <<"\" is not a known command, package, black box type or black box name");
1441 if (words[2]=="all")
1443 if ( words[1]=="packages" )
1445 GetExecuter()->GetFactory()->PrintPackages(true,true);
1450 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1452 catch (bbtk::Exception f)
1458 HelpCommand(words[0]);
1459 bbtkError(words[0]<<" : syntax error");
1464 bbtkError("Should not reach here !!!");
1467 //=======================================================================
1469 //===================================================================
1470 /// Displays the Configuration
1471 void Interpreter::Config() const
1473 ConfigurationFile::GetInstance().GetHelp(1);
1475 //===================================================================
1477 //=======================================================================
1478 /// Displays help on all the commands
1479 void Interpreter::HelpCommands()
1481 std::cout << "Available commands :" << std::endl;
1482 CommandDictType::iterator i;
1483 for ( i = mCommandDict.begin();
1484 i != mCommandDict.end();
1486 std::cout << " " << i->first << std::endl;
1487 // std::cout << " usage : " << i->second.syntax << std::endl;
1488 // std::cout << " " << i->second.help << std::endl;
1492 //=======================================================================
1495 //=======================================================================
1496 /// Displays help on a particular commands
1497 void Interpreter::HelpCommand(const std::string& s)
1499 CommandDictType::iterator c;
1500 c = mCommandDict.find(s);
1501 if ( c == mCommandDict.end() ) {
1502 bbtkError(s<<" : Unknown command");
1504 // std::cout << " " << s << " : "<< std::endl;
1505 // CommandParamDictType::iterator i;
1506 // for ( i = c->second.begin();
1507 // i != c->second.end();
1509 std::cout << " usage : " << c->second.syntax << std::endl;
1510 std::cout << " " << c->second.help << std::endl;
1513 //=======================================================================
1516 //=======================================================================
1517 /// Fills the vector commands with the commands which
1518 /// have the first n chars of buf for prefix
1519 /// TODO : skip initial spaces in buf and also return the position of first
1520 /// non blank char in buf
1521 void Interpreter::FindCommandsWithPrefix( char* buf,
1523 std::vector<std::string>& commands )
1525 CommandDictType::const_iterator i;
1526 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1528 if ((i->first).find(buf,0,n) == 0)
1529 commands.push_back(i->first);
1532 //=======================================================================
1536 //=======================================================================
1537 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1539 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1540 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1542 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1543 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1544 // E.G. STORE THIS IN bbtk_config.xml
1545 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1546 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1547 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1548 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1549 #define BBTK_BACKSPACE_KBCODE 0x00000008
1550 #define BBTK_DEL_KBCODE 0x0000007F
1551 #define BBTK_SPACE_KBCODE 0x00000020
1553 //=======================================================================
1554 void Interpreter::GetLineFromPrompt(std::string& s)
1559 int MAX_LINE_SIZE = 160;
1560 int MAX_HISTORY_SIZE = 100;
1562 char* newline = new char[MAX_LINE_SIZE];
1563 memset(newline,0,MAX_LINE_SIZE);
1564 char* histline = new char[MAX_LINE_SIZE];
1565 memset(histline,0,MAX_LINE_SIZE);
1567 char* line = newline;
1568 int hist = mHistory.size();
1574 read ( STDIN_FILENO, &c, 4) ;
1576 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1578 // Printable character
1579 if ( (ind<MAX_LINE_SIZE-1) &&
1580 ( c >= BBTK_SPACE_KBCODE ) &&
1581 ( c < BBTK_DEL_KBCODE ))
1589 // delete the unused line
1595 // empty lines are not stored in from history
1598 // if history too long : delete oldest command
1599 if (mHistory.size()>MAX_HISTORY_SIZE)
1601 delete mHistory.front();
1602 mHistory.pop_front();
1604 mHistory.push_back(line);
1609 else if ( (ind>0) &&
1610 ((c == BBTK_BACKSPACE_KBCODE) ||
1611 (c == BBTK_DEL_KBCODE)) )
1619 // TODO : Command completion
1620 std::vector<std::string> commands;
1621 FindCommandsWithPrefix( line,ind,commands);
1622 if (commands.size()==1)
1624 std::string com = *commands.begin();
1625 for (; ind<com.size(); ++ind)
1627 PrintChar(com[ind]);
1633 else if (commands.size()>1)
1635 std::vector<std::string>::iterator i;
1637 for (i=commands.begin();i!=commands.end();++i)
1639 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1642 write(STDOUT_FILENO,"\n> ",3);
1643 //for (int j=0;j<ind;++j)
1645 write(STDOUT_FILENO,line,ind);
1649 // Arrow up : back in history
1650 else if (c==BBTK_UP_ARROW_KBCODE)
1654 // erase current line
1655 while (ind--) BackSpace();
1659 strcpy(histline,mHistory[hist]);
1663 write(STDOUT_FILENO,line,ind);
1666 // Arrow down : down in history
1667 else if (c==BBTK_DOWN_ARROW_KBCODE)
1669 if (hist<mHistory.size()-1)
1671 // erase current line
1672 while (ind--) BackSpace();
1676 strcpy(histline,mHistory[hist]);
1680 write(STDOUT_FILENO,line,ind);
1682 // end of history : switch back to newline
1683 else if (hist==mHistory.size()-1)
1685 // erase current line
1686 while (ind--) BackSpace();
1693 write(STDOUT_FILENO,line,ind);
1697 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1699 PrintChar(line[ind]);
1704 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1712 write(STDOUT_FILENO,"\n\r",2);
1720 //=======================================================================
1721 void Interpreter::GetLineFromPrompt(std::string& s)
1747 //=======================================================================
1753 //=======================================================================
1754 void Interpreter::CommandLineInterpreter()
1756 bbtkDebugMessageInc("Interpreter",9,
1757 "Interpreter::CommandLineInterpreter()"<<std::endl);
1759 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1760 // Initialise the tty in non canonical mode with no echo
1761 // oter remembers the previous settings to restore them after
1762 struct termios ter,oter;
1765 ter.c_lflag &= ~ECHO;
1766 ter.c_lflag &= ~ICANON;
1769 tcsetattr(0,TCSANOW,&ter);
1772 mCommandLine = true;
1774 bool insideComment = false; // for multiline comment
1780 GetLineFromPrompt(line);
1781 InterpretLine(line, insideComment);
1783 catch (QuitException e)
1785 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1788 catch (bbtk::Exception e)
1792 catch (std::exception& e)
1794 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1798 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1803 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1804 tcsetattr(0,TCSANOW,&oter);
1807 std::cout << "Good bye !" << std::endl;
1809 bbtkDebugDecTab("Interpreter",9);
1812 //=======================================================================
1813 void Interpreter::Graph(const std::vector<std::string>& words)
1816 bool system_display = true;
1818 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1819 system_display = false;
1821 if (words.size()==1)
1823 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1825 else if (words.size()==2)
1827 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1829 else if (words.size()==3)
1831 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1833 else if (words.size()==4)
1835 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1837 else if (words.size()==5)
1839 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1841 else if (words.size()==6)
1843 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1845 else if (words.size()==7)
1847 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1850 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1851 mUser->InterpreterUserViewHtmlPage(page);
1854 //=======================================================================
1857 //=======================================================================
1858 void Interpreter::Index(const std::string& filename,
1859 const std::string& type)
1861 Factory::IndexEntryType t;
1862 if (type=="Initials") t = Factory::Initials;
1863 else if (type=="Categories") t = Factory::Categories;
1864 else if (type=="Packages") t = Factory::Packages;
1865 else if (type=="Adaptors") t = Factory::Adaptors;
1867 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1869 //=======================================================================