1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/26 08:51:43 $
7 Version: $Revision: 1.56 $
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",3,
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 if ( Utilities::IsDirectory( upath ) )
1002 script_paths.push_back(upath);
1006 bbtkError("'"<<upath<<"' : not a valid folder");
1009 // ==== relative path provided : search all bbs path appended with
1010 // the relative path provided
1013 std::vector<std::string>::const_iterator i;
1014 for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1015 i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1018 std::string full_path(*i);
1019 // we *really* want '.' to be the current working directory
1020 if (full_path == ".") {
1021 char buf[2048]; // for getcwd
1022 char * currentDir = getcwd(buf, 2048);
1023 std::string cwd(currentDir);
1024 full_path = currentDir;
1027 full_path += ConfigurationFile::GetInstance().Get_file_separator();
1030 if ( Utilities::IsDirectory( full_path ) )
1032 script_paths.push_back(full_path);
1036 // === search paths list complete : now explore it
1037 if (script_paths.empty())
1039 bbtkMessage("Interpreter",1,
1040 "'"<<upath<<"' : No matching folder" << std::endl);
1044 std::vector<std::string>::iterator i;
1045 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1047 bbtkMessage("Interpreter",1,
1048 "--> Looking in '" << *i << "'" << std::endl);
1052 int nbFiles = Utilities::Explore(*i, false, Filenames);
1055 for (std::vector<std::string>::iterator j = Filenames.begin();
1056 j!= Filenames.end(); ++j)
1058 int lgr = (*j).size();
1060 continue; // ignore non .bbs file
1061 if ((*j).substr(lgr-4, 4) != ".bbs")
1064 (*stream) << "include \"" << *j << "\"\n";
1065 bbtkMessage("Interpreter",2,
1066 " --> Found '" << *j << "'" << std::endl);
1073 bbtkMessage("Interpreter",1,
1074 " --> No .bbs found"<< std::endl);
1078 bbtkMessage("Interpreter",1,
1079 " --> "<<nbBssFiles<<" .bbs found"<< std::endl);
1080 SwitchToStream(stream);
1083 //break; // a directory was found; we stop iterating
1084 // LG : No! We want all files included !
1088 //=============== end pkgname=="*" ===========
1091 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1092 // (not only a plain script name)
1093 // we trust him, and try to expland the directory name
1094 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1096 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1099 // ===========================================================check user supplied location
1100 fullnameGiven = true;
1102 fullPathScriptName = Utilities::ExpandLibName(name, false);
1104 // allow user to always forget ".bbs"
1105 int l = fullPathScriptName.size();
1111 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1113 fullPathScriptName = fullPathScriptName + ".bbs";
1118 fullPathScriptName = fullPathScriptName + ".bbs";
1121 if ( Utilities::FileExists(fullPathScriptName))
1128 // =============================== iterate on the paths
1130 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1132 std::vector<std::string>::iterator i;
1133 for (i=script_paths.begin();i!=script_paths.end();++i)
1136 // we *really* want '.' to be the current working directory
1138 char buf[2048]; // for getcwd
1139 char * currentDir = getcwd(buf, 2048);
1140 std::string cwd(currentDir);
1144 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1146 // Check if library exists
1147 if ( ! Utilities::FileExists(fullPathScriptName) )
1149 // The following is *NOT* a debug time message :
1150 // It's a user intended message.
1151 // Please don't remove it.
1152 bbtkMessage("Interpreter",2,
1153 " [" <<fullPathScriptName <<"] : doesn't exist"
1155 continue; // try next path
1157 bbtkMessage("Interpreter",2,
1158 " [" <<fullPathScriptName
1159 <<"] : found" <<std::endl);
1161 break; // a script was found; we stop iterating
1163 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1169 if(fullPathScriptName == "")
1170 bbtkError("Path ["<<upath<<"] doesn't exist");
1172 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1174 bbtkError("No ["<<pkgname<<".bbs] script found");
1178 LoadScript(fullPathScriptName,name);
1182 //=======================================================================
1185 //=======================================================================
1186 void Interpreter::SwitchToStream( std::stringstream* stream )
1188 mFile.push_back(stream);
1189 std::ostringstream buffer_name;
1191 buffer_name << "buffer_" ;
1193 if (mFileName.size()>0 )
1195 buffer_name << mFileName.back() << "_" << mLine.back();
1197 mFileName.push_back(buffer_name.str());
1198 mIncludeFileName.push_back(buffer_name.str());
1201 //=======================================================================
1203 //=======================================================================
1205 void Interpreter::LoadScript( std::string fullPathScriptName,
1206 std::string includeScriptName)
1208 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1210 bool okScriptExist=false;
1211 int iStrScript,sizeVecStricpt=mFileName.size();
1212 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1214 if (mFileName[iStrScript] == fullPathScriptName )
1220 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1221 // if (okScriptExist==true)
1223 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1224 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1229 s = new std::ifstream;
1230 s->open(fullPathScriptName.c_str());
1233 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1237 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1238 << "] found" << std::endl);
1241 mFileName.push_back(fullPathScriptName);
1242 mIncludeFileName.push_back(includeScriptName);
1248 //=======================================================================
1252 void Interpreter::CloseCurrentFile()
1254 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1257 if (mFile.size()==0)
1259 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1263 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1265 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1266 if (file!=0) file->close();
1268 delete mFile.back();
1270 mFileName.pop_back();
1271 mIncludeFileName.pop_back();
1274 bbtkDebugMessage("Interpreter",9," Remains "
1276 <<" open"<<std::endl);
1277 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1280 //=======================================================================
1282 //=======================================================================
1286 void Interpreter::CloseAllFiles()
1288 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1291 while (mFile.size() != 0)
1295 mFile.back()->close();
1296 delete mFile.back();
1298 bbtkDebugMessage("Interpreter",9,
1299 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1300 mFileName.pop_back();
1301 mIncludeFileName.pop_back();
1305 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1308 //=======================================================================
1312 //=======================================================================
1316 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1317 CommandInfoType& info )
1319 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1321 // searches the command category
1322 CommandDictType::iterator c;
1323 c = mCommandDict.find(words[0]);
1324 if ( c == mCommandDict.end() ) {
1325 bbtkError(words[0]<<" : unknown command");
1328 // tests the number of args
1329 if ( ( words.size()-1 < c->second.argmin ) ||
1330 ( words.size()-1 > c->second.argmax ) )
1332 HelpCommand(words[0]);
1333 bbtkError(words[0]<<" : wrong number of arguments");
1337 bbtkDecTab("Interpreter",9);
1339 //=======================================================================
1342 //=======================================================================
1343 /// Displays help on all the commands
1344 void Interpreter::Help(const std::vector<std::string>& words)
1346 unsigned int nbarg = words.size()-1;
1354 if (words[1]=="packages")
1356 GetExecuter()->GetFactory()->PrintPackages(true);
1361 HelpCommand(words[1]);
1363 catch (bbtk::Exception e)
1367 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1371 ConfigurationFile::GetInstance().Get_doc_path();
1372 url += "/bbdoc/" + words[1] + "/index.html";
1373 if (Utilities::FileExists(url))
1375 mUser->InterpreterUserViewHtmlPage(url);
1379 catch (bbtk::Exception f)
1383 std::string package;
1384 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1388 ConfigurationFile::GetInstance().Get_doc_path();
1389 url += "/bbdoc/" + package + "/index.html";
1390 if (Utilities::FileExists(url))
1392 url += "#" + words[1];
1393 mUser->InterpreterUserViewHtmlPage(url);
1397 catch (bbtk::Exception g)
1401 GetExecuter()->ShowRelations(words[1],"0","9999");
1403 catch (bbtk::Exception h){
1404 bbtkError("\""<<words[1].c_str()
1405 <<"\" is not a known command, package, black box type or black box name");
1413 if (words[2]=="all")
1415 if ( words[1]=="packages" )
1417 GetExecuter()->GetFactory()->PrintPackages(true,true);
1422 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1424 catch (bbtk::Exception f)
1430 HelpCommand(words[0]);
1431 bbtkError(words[0]<<" : syntax error");
1436 bbtkError("Should not reach here !!!");
1439 //=======================================================================
1441 //===================================================================
1442 /// Displays the Configuration
1443 void Interpreter::Config() const
1445 ConfigurationFile::GetInstance().GetHelp(1);
1447 //===================================================================
1449 //=======================================================================
1450 /// Displays help on all the commands
1451 void Interpreter::HelpCommands()
1453 std::cout << "Available commands :" << std::endl;
1454 CommandDictType::iterator i;
1455 for ( i = mCommandDict.begin();
1456 i != mCommandDict.end();
1458 std::cout << " " << i->first << std::endl;
1459 // std::cout << " usage : " << i->second.syntax << std::endl;
1460 // std::cout << " " << i->second.help << std::endl;
1464 //=======================================================================
1467 //=======================================================================
1468 /// Displays help on a particular commands
1469 void Interpreter::HelpCommand(const std::string& s)
1471 CommandDictType::iterator c;
1472 c = mCommandDict.find(s);
1473 if ( c == mCommandDict.end() ) {
1474 bbtkError(s<<" : Unknown command");
1476 // std::cout << " " << s << " : "<< std::endl;
1477 // CommandParamDictType::iterator i;
1478 // for ( i = c->second.begin();
1479 // i != c->second.end();
1481 std::cout << " usage : " << c->second.syntax << std::endl;
1482 std::cout << " " << c->second.help << std::endl;
1485 //=======================================================================
1488 //=======================================================================
1489 /// Fills the vector commands with the commands which
1490 /// have the first n chars of buf for prefix
1491 /// TODO : skip initial spaces in buf and also return the position of first
1492 /// non blank char in buf
1493 void Interpreter::FindCommandsWithPrefix( char* buf,
1495 std::vector<std::string>& commands )
1497 CommandDictType::const_iterator i;
1498 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1500 if ((i->first).find(buf,0,n) == 0)
1501 commands.push_back(i->first);
1504 //=======================================================================
1508 //=======================================================================
1509 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1511 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1512 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1514 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1515 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1516 // E.G. STORE THIS IN bbtk_config.xml
1517 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1518 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1519 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1520 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1521 #define BBTK_BACKSPACE_KBCODE 0x00000008
1522 #define BBTK_DEL_KBCODE 0x0000007F
1523 #define BBTK_SPACE_KBCODE 0x00000020
1525 //=======================================================================
1526 void Interpreter::GetLineFromPrompt(std::string& s)
1531 int MAX_LINE_SIZE = 160;
1532 int MAX_HISTORY_SIZE = 100;
1534 char* newline = new char[MAX_LINE_SIZE];
1535 memset(newline,0,MAX_LINE_SIZE);
1536 char* histline = new char[MAX_LINE_SIZE];
1537 memset(histline,0,MAX_LINE_SIZE);
1539 char* line = newline;
1540 int hist = mHistory.size();
1546 read ( STDIN_FILENO, &c, 4) ;
1548 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1550 // Printable character
1551 if ( (ind<MAX_LINE_SIZE-1) &&
1552 ( c >= BBTK_SPACE_KBCODE ) &&
1553 ( c < BBTK_DEL_KBCODE ))
1561 // delete the unused line
1567 // empty lines are not stored in from history
1570 // if history too long : delete oldest command
1571 if (mHistory.size()>MAX_HISTORY_SIZE)
1573 delete mHistory.front();
1574 mHistory.pop_front();
1576 mHistory.push_back(line);
1581 else if ( (ind>0) &&
1582 ((c == BBTK_BACKSPACE_KBCODE) ||
1583 (c == BBTK_DEL_KBCODE)) )
1591 // TODO : Command completion
1592 std::vector<std::string> commands;
1593 FindCommandsWithPrefix( line,ind,commands);
1594 if (commands.size()==1)
1596 std::string com = *commands.begin();
1597 for (; ind<com.size(); ++ind)
1599 PrintChar(com[ind]);
1605 else if (commands.size()>1)
1607 std::vector<std::string>::iterator i;
1609 for (i=commands.begin();i!=commands.end();++i)
1611 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1614 write(STDOUT_FILENO,"\n> ",3);
1615 //for (int j=0;j<ind;++j)
1617 write(STDOUT_FILENO,line,ind);
1621 // Arrow up : back in history
1622 else if (c==BBTK_UP_ARROW_KBCODE)
1626 // erase current line
1627 while (ind--) BackSpace();
1631 strcpy(histline,mHistory[hist]);
1635 write(STDOUT_FILENO,line,ind);
1638 // Arrow down : down in history
1639 else if (c==BBTK_DOWN_ARROW_KBCODE)
1641 if (hist<mHistory.size()-1)
1643 // erase current line
1644 while (ind--) BackSpace();
1648 strcpy(histline,mHistory[hist]);
1652 write(STDOUT_FILENO,line,ind);
1654 // end of history : switch back to newline
1655 else if (hist==mHistory.size()-1)
1657 // erase current line
1658 while (ind--) BackSpace();
1665 write(STDOUT_FILENO,line,ind);
1669 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1671 PrintChar(line[ind]);
1676 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1684 write(STDOUT_FILENO,"\n\r",2);
1692 //=======================================================================
1693 void Interpreter::GetLineFromPrompt(std::string& s)
1719 //=======================================================================
1725 //=======================================================================
1726 void Interpreter::CommandLineInterpreter()
1728 bbtkDebugMessageInc("Interpreter",9,
1729 "Interpreter::CommandLineInterpreter()"<<std::endl);
1731 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1732 // Initialise the tty in non canonical mode with no echo
1733 // oter remembers the previous settings to restore them after
1734 struct termios ter,oter;
1737 ter.c_lflag &= ~ECHO;
1738 ter.c_lflag &= ~ICANON;
1741 tcsetattr(0,TCSANOW,&ter);
1744 mCommandLine = true;
1746 bool insideComment = false; // for multiline comment
1752 GetLineFromPrompt(line);
1753 InterpretLine(line, insideComment);
1755 catch (QuitException e)
1757 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1760 catch (bbtk::Exception e)
1764 catch (std::exception& e)
1766 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1770 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1775 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1776 tcsetattr(0,TCSANOW,&oter);
1779 std::cout << "Good bye !" << std::endl;
1781 bbtkDebugDecTab("Interpreter",9);
1784 //=======================================================================
1785 void Interpreter::Graph(const std::vector<std::string>& words)
1788 bool system_display = true;
1790 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1791 system_display = false;
1793 if (words.size()==1)
1795 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1797 else if (words.size()==2)
1799 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1801 else if (words.size()==3)
1803 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1805 else if (words.size()==4)
1807 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1809 else if (words.size()==5)
1811 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1813 else if (words.size()==6)
1815 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1817 else if (words.size()==7)
1819 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1822 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1823 mUser->InterpreterUserViewHtmlPage(page);
1826 //=======================================================================
1829 //=======================================================================
1830 void Interpreter::Index(const std::string& filename,
1831 const std::string& type)
1833 Factory::IndexEntryType t;
1834 if (type=="Initials") t = Factory::Initials;
1835 else if (type=="Categories") t = Factory::Categories;
1836 else if (type=="Packages") t = Factory::Packages;
1837 else if (type=="Adaptors") t = Factory::Adaptors;
1839 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1841 //=======================================================================