1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/21 14:59:39 $
7 Version: $Revision: 1.52 $
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();
335 throw InterpreterError(e,in_script,file,line);
339 std::stringstream mess;
340 mess << "* ERROR : "<<e.GetMessage()<<std::endl;
341 if (mFileName.size()) {
342 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
343 mess << "* LINE : "<<mLine.back()<<std::endl;
345 std::cerr << mess.str();
348 //=======================================================================
350 //=======================================================================
351 void Interpreter::CatchStdException( const std::exception& e )
355 bool in_script = false;
356 std::string file("");
358 if (mFileName.size()) {
359 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
360 if (fs!=0) in_script = true;
361 file = mFileName.back();
364 throw InterpreterError(e.what(),in_script,file,line);
368 std::stringstream mess;
369 mess << "* ERROR : "<<e.what()<<std::endl;
370 if (mFileName.size()) {
371 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
372 mess << "* LINE : "<<mLine.back()<<std::endl;
374 std::cerr << mess.str();
377 //=======================================================================
379 //=======================================================================
380 void Interpreter::CatchUnknownException()
384 bool in_script = false;
385 std::string file("");
387 if (mFileName.size()) {
388 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
389 if (fs!=0) in_script = true;
390 file = mFileName.back();
393 throw InterpreterError("Unknown exception caught",
394 in_script,file,line);
398 std::stringstream mess;
399 mess << "* UNDEFINED ERROR (not a bbtk nor a std exception)"
401 if (mFileName.size()) {
402 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
403 mess << "* LINE : "<<mLine.back()<<std::endl;
405 std::cerr << mess.str();
408 //=======================================================================
410 //=======================================================================
412 #define CATCH_MACRO \
413 catch (QuitException e) \
415 status = Interpreter_QUIT; \
416 if (mThrow) throw QuitException(); \
418 catch (bbtk::Exception e) \
420 status = Interpreter_ERROR; \
421 CatchBbtkException(e); \
423 catch (std::exception& e) \
425 status = Interpreter_ERROR; \
426 CatchStdException(e); \
430 status = Interpreter_ERROR; \
431 CatchUnknownException(); \
433 //=======================================================================
436 //=======================================================================
440 Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
442 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
444 bool exm = mCommandLine;
445 mCommandLine = false;
447 ExitStatus status = Interpreter_OK;
451 SwitchToFile(filename);
453 bool insideComment = false; // for multiline comment
454 while (mFile.size()>0)
456 while (!mFile.back()->eof()) {
459 mFile.back()->getline(buf,500);
460 std::string str(buf);
461 int size=str.length();
462 if ( str[ size-1 ]==13 )
467 InterpretLine(str, insideComment);
476 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
477 bbtkDecTab("Interpreter",9);
483 //=======================================================================
486 //=======================================================================
490 Interpreter::ExitStatus
491 Interpreter::InterpretBuffer( std::stringstream* buffer )
493 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
495 bool exm = mCommandLine;
496 mCommandLine = false;
498 ExitStatus status = Interpreter_OK;
502 SwitchToStream(buffer);
503 bool insideComment = false; // for multiline comment
504 while (mFile.size()>0)
506 while (!mFile.back()->eof()) {
509 mFile.back()->getline(buf,500);
510 std::string str(buf);
512 int size=str.length();
513 if ( str[ size-1 ]==13 )
518 InterpretLine(str, insideComment);
528 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
529 bbtkDecTab("Interpreter",9);
534 //=======================================================================
536 //=======================================================================
537 /// Runs the interpretation of a command
538 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
540 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
542 ExitStatus status = Interpreter_OK;
546 bool insideComment = false;
547 InterpretLine(line, insideComment);
551 catch (QuitException e)
553 status = Interpreter_QUIT;
555 catch (bbtk::Exception e)
557 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
558 status = Interpreter_ERROR;
560 catch (std::exception& e)
562 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
563 status = Interpreter_ERROR;
568 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
569 status = Interpreter_ERROR;
573 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
575 bbtkDecTab("Interpreter",9);
581 //=======================================================================
585 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
587 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
588 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
590 std::vector<std::string> words;
591 SplitLine(line,words);
596 bbtkDebugDecTab("Interpreter",9);
600 // Single line comment : # or //
601 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
603 bbtkDebugDecTab("Interpreter",9);
604 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
608 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
610 if (words[0][0]=='/' && words[0][1]=='*')
612 bbtkDebugDecTab("Interpreter",9);
613 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
614 insideComment = true;
618 if (words[0][0]=='*' && words[0][1]=='/')
620 bbtkDebugDecTab("Interpreter",9);
621 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
622 if ( !insideComment ) {
623 bbtkDebugDecTab("Interpreter",9);
624 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
626 insideComment = false;
632 bbtkDebugDecTab("Interpreter",9);
633 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
638 CommandInfoType command;
639 InterpretCommand(words,command);
641 bbtkDebugMessage("Interpreter",9,
642 "Command='"<<command.category
643 <<"' code="<<command.code<<std::endl);
645 std::string left,right,left2,right2;
646 std::string filename;
647 switch (command.code)
650 mExecuter->Create(words[1],words[2]);
655 // mExecuter->Remove(words[1]);
659 Utilities::SplitAroundFirstDot(words[1],left,right);
660 Utilities::SplitAroundFirstDot(words[2],left2,right2);
661 mExecuter->Connect(left,right,left2,right2);
665 mExecuter->BeginPackage(words[1]);
669 mExecuter->EndPackage();
673 if (mFileName.size()>0)
675 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
679 mExecuter->Define(words[1],"",filename);
683 mExecuter->Define(words[1],words[2],filename);
688 mExecuter->EndDefine();
692 Print(words[1]); /// \todo use generate command
696 if (words[1]=="freeze")
697 mExecuter->SetNoExecMode(true);
698 else if (words[1]=="unfreeze")
699 mExecuter->SetNoExecMode(false);
701 mExecuter->Update(words[1]);
705 Utilities::SplitAroundFirstDot(words[2],left,right);
706 mExecuter->DefineInput(words[1],left,right,words[3]);
710 Utilities::SplitAroundFirstDot(words[2],left,right);
711 mExecuter->DefineOutput(words[1],left,right,words[3]);
715 Utilities::SplitAroundFirstDot(words[1],left,right);
716 mExecuter->Set(left,right,words[2]);
720 mExecuter->Author(words[1]);
724 mExecuter->Category(words[1]);
729 Index("tmp_index.html");
730 else if (words.size()==2)
732 else if (words.size()==3)
733 Index(words[1],words[2]);
737 mExecuter->Description(words[1]);
747 bbtk::MessageManager::PrintInfo();
751 sscanf(words[2].c_str(),"%d",&level);
752 bbtk::MessageManager::SetMessageLevel(words[1],level);
765 this->mExecuter->Reset();
771 InterpretFile(words[1]);
775 SwitchToFile(words[1]);
777 // if 'source' was given
780 GetExecuter()->SetCurrentFileName(words[1]);
785 GetExecuter()->GetFactory()->LoadPackage(words[1]);
789 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
794 throw QuitException();
798 if (words.size() == 2)
800 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
801 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
805 mExecuter->SetWorkspaceName(words[2]);
810 bbtkInternalError("should not reach here !!!");
813 bbtkDecTab("Interpreter",9);
815 //=======================================================================
821 //=======================================================================
825 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
827 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
829 std::string delimiters = "\"";
830 std::vector<std::string> quote;
831 Utilities::SplitString(str,delimiters,quote);
834 std::vector<std::string>::iterator i;
835 for (i=quote.begin(); i!=quote.end(); )
837 Utilities::SplitString(*i,delimiters,tokens);
841 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
842 tokens.push_back(*i);
847 for (i=tokens.begin(); i!=tokens.end(); ++i)
849 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
851 bbtkDebugMessageCont("Interpreter",9,std::endl);
853 bbtkDebugDecTab("Interpreter",9);
855 //=======================================================================
858 //=======================================================================
859 // Replaces substrings "\\n" by a real carriage return "\n"
860 void SubsBackslashN ( std::string& s )
862 std::string ss("\\n");
863 std::string::size_type pos = 0;
866 while ( pos != std::string::npos )
868 s.replace(pos,2,cr,1);
869 pos = s.find(ss, pos-1);
872 //=======================================================================
875 //=======================================================================
879 void Interpreter::Print( const std::string& str)
881 if (mExecuter->GetNoExecMode()) return;
883 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
886 // InterpretLine ("load std")
887 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
888 // InterpretLine("new Print _P_")
889 // InterpretLine("connect _C_.Out _P_.In")
893 std::vector<std::string> chains;
894 std::string delimiters("$");
896 // Skip delimiters at beginning.
897 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
899 if (lastPos>0) is_text = false;
901 // Find first delimiter.
902 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
904 while (std::string::npos != pos || std::string::npos != lastPos)
908 // Found a text token, add it to the vector.
909 chains.push_back(str.substr(lastPos, pos - lastPos));
910 // std::string token = str.substr(lastPos, pos - lastPos)
911 // InterpretLine("set _C_.In%num% %token%")
917 // is an output (between $$) : decode
918 std::string tok,box,output;
919 tok = str.substr(lastPos, pos - lastPos);
920 Utilities::SplitAroundFirstDot(tok,box,output);
921 chains.push_back( mExecuter->Get(box,output) );
923 // InterpretLine("connect %tok% _C_.In%num%")
926 // Skip delimiters. Note the "not_of"
927 lastPos = str.find_first_not_of(delimiters, pos);
928 // Find next delimiter
929 pos = str.find_first_of(delimiters, lastPos);
934 // InterpretLine("exec _P_")
935 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
937 std::vector<std::string>::iterator i;
938 for (i= chains.begin(); i!=chains.end(); ++i)
940 // bbtkMessage("Echo",1,*i);
944 std::cout << std::endl;
945 bbtkDebugDecTab("Interpreter",9);
948 //=======================================================================
953 // ===================================================================================
955 void Interpreter::SwitchToFile( const std::string& name )
957 // Note : in the following :
958 // name : the user supplied name
959 // - abreviated name e.g. scr scr.bbs
960 // - relative full name e.g. ./scr.bbs ../../scr.bbs
961 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
962 // same for Windows, with c:, d: ...
964 // use ./directory/subdir/scrname.bbs
967 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
968 <<name<<"\")"<<std::endl);
970 std::vector<std::string> script_paths;
971 std::string fullPathScriptName; // full path script name
972 std::string pkgname; // e.g. <scriptname>.bbs
973 std::vector<std::string> Filenames;
975 // The following is *NOT* a debug time message :
976 // It's a user intended message.
977 // Please don't remove it.
978 bbtkMessage("Interpreter",1,
979 "look for : [" << name
980 << "]" << std::endl);
981 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
984 pkgname = Utilities::ExtractScriptName(name,upath);
986 bbtkMessage("Interpreter",1,
987 "extract : pkgname [" << pkgname
988 << "] upath [" << upath << "]" << std::endl);
989 bool fullnameGiven = false;
990 bool foundFile = false;
992 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
996 std::stringstream* stream = new std::stringstream;
997 //if (upath.size()!=0) // avoid troubles for "*"
999 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
1001 int nbFiles = Utilities::Explore(upath, false, Filenames);
1003 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1005 int lgr = (*i).size();
1007 continue; // ignore non .bbs file
1008 if ((*i).substr(lgr-4, 4) != ".bbs")
1011 (*stream) << "include " << *i << "\n";
1016 bbtkMessage("Interpreter",2,
1017 "WARNING : No '.bbs' file found in ["
1018 << upath << "]" << std::endl);
1020 SwitchToStream(stream);
1026 std::vector<std::string>::iterator i;
1027 std::string fullDirectoryName;
1028 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1032 // we *really* want '.' to be the current working directory
1034 char buf[2048]; // for getcwd
1035 char * currentDir = getcwd(buf, 2048);
1036 std::string cwd(currentDir);
1040 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
1042 // without last slash "\"
1043 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
1045 // Check if library exists
1046 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
1048 // The following is *NOT* a debug time message :
1049 // It's a user intended message.
1050 // Please don't remove it.
1051 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
1052 <<"] : doesn't exist" <<std::endl);
1053 continue; // try next path
1058 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
1061 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1063 int lgr = (*i).size();
1065 continue; // ignore non .bbs file
1066 if ((*i).substr(lgr-4, 4) != ".bbs")
1069 (*stream) << "include " << *i << "\n";
1073 bbtkMessage("Interpreter",1,
1074 "WARNING : No '.bbs' file found in ["
1075 << fullDirectoryName << "]" << std::endl);
1077 SwitchToStream(stream);
1080 //break; // a directory was found; we stop iterating
1081 // LG : No! We want all files included !
1086 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1087 // (not only a plain script name)
1088 // we trust him, and try to expland the directory name
1089 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1091 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1094 // ===========================================================check user supplied location
1095 fullnameGiven = true;
1097 fullPathScriptName = Utilities::ExpandLibName(name, false);
1099 // allow user to always forget ".bbs"
1100 int l = fullPathScriptName.size();
1106 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1108 fullPathScriptName = fullPathScriptName + ".bbs";
1113 fullPathScriptName = fullPathScriptName + ".bbs";
1116 if ( Utilities::FileExists(fullPathScriptName))
1123 // =============================================================== iterate on the paths
1126 std::vector<std::string>::iterator i;
1127 for (i=script_paths.begin();i!=script_paths.end();++i)
1130 // we *really* want '.' to be the current working directory
1132 char buf[2048]; // for getcwd
1133 char * currentDir = getcwd(buf, 2048);
1134 std::string cwd(currentDir);
1138 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1140 // Check if library exists
1141 if ( ! Utilities::FileExists(fullPathScriptName) )
1143 // The following is *NOT* a debug time message :
1144 // It's a user intended message.
1145 // Please don't remove it.
1146 bbtkMessage("Interpreter",2,
1147 " [" <<fullPathScriptName <<"] : doesn't exist"
1149 continue; // try next path
1151 bbtkMessage("Interpreter",2,
1152 " [" <<fullPathScriptName
1153 <<"] : found" <<std::endl);
1155 break; // a script was found; we stop iterating
1157 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1163 if(fullPathScriptName == "")
1164 bbtkError("Path ["<<upath<<"] doesn't exist");
1166 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1168 bbtkError("No ["<<pkgname<<".bbs] script found");
1172 LoadScript(fullPathScriptName,name);
1178 void Interpreter::SwitchToStream( std::stringstream* stream )
1180 mFile.push_back(stream);
1181 std::ostringstream buffer_name;
1183 buffer_name << "buffer_" ;
1185 if (mFileName.size()>0 )
1187 buffer_name << mFileName.back() << "_" << mLine.back();
1189 mFileName.push_back(buffer_name.str());
1190 mIncludeFileName.push_back(buffer_name.str());
1194 //=======================================================================
1196 void Interpreter::LoadScript( std::string fullPathScriptName,
1197 std::string includeScriptName)
1199 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1201 bool okScriptExist=false;
1202 int iStrScript,sizeVecStricpt=mFileName.size();
1203 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1205 if (mFileName[iStrScript] == fullPathScriptName )
1211 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1212 // if (okScriptExist==true)
1214 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1215 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1220 s = new std::ifstream;
1221 s->open(fullPathScriptName.c_str());
1224 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1228 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1229 << "] found" << std::endl);
1232 mFileName.push_back(fullPathScriptName);
1233 mIncludeFileName.push_back(includeScriptName);
1239 //=======================================================================
1243 void Interpreter::CloseCurrentFile()
1245 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1248 if (mFile.size()==0)
1250 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1254 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1256 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1257 if (file!=0) file->close();
1259 delete mFile.back();
1261 mFileName.pop_back();
1262 mIncludeFileName.pop_back();
1265 bbtkDebugMessage("Interpreter",9," Remains "
1267 <<" open"<<std::endl);
1268 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1271 //=======================================================================
1273 //=======================================================================
1277 void Interpreter::CloseAllFiles()
1279 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1282 while (mFile.size() != 0)
1286 mFile.back()->close();
1287 delete mFile.back();
1289 bbtkDebugMessage("Interpreter",9,
1290 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1291 mFileName.pop_back();
1292 mIncludeFileName.pop_back();
1296 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1299 //=======================================================================
1303 //=======================================================================
1307 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1308 CommandInfoType& info )
1310 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1312 // searches the command category
1313 CommandDictType::iterator c;
1314 c = mCommandDict.find(words[0]);
1315 if ( c == mCommandDict.end() ) {
1316 bbtkError(words[0]<<" : unknown command");
1319 // tests the number of args
1320 if ( ( words.size()-1 < c->second.argmin ) ||
1321 ( words.size()-1 > c->second.argmax ) )
1323 HelpCommand(words[0]);
1324 bbtkError(words[0]<<" : wrong number of arguments");
1328 bbtkDecTab("Interpreter",9);
1330 //=======================================================================
1333 //=======================================================================
1334 /// Displays help on all the commands
1335 void Interpreter::Help(const std::vector<std::string>& words)
1337 unsigned int nbarg = words.size()-1;
1345 if (words[1]=="packages")
1347 GetExecuter()->GetFactory()->PrintPackages(true);
1352 HelpCommand(words[1]);
1354 catch (bbtk::Exception e)
1358 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1362 ConfigurationFile::GetInstance().Get_doc_path();
1363 url += "/bbdoc/" + words[1] + "/index.html";
1364 if (Utilities::FileExists(url))
1366 mUser->InterpreterUserViewHtmlPage(url);
1370 catch (bbtk::Exception f)
1374 std::string package;
1375 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1379 ConfigurationFile::GetInstance().Get_doc_path();
1380 url += "/bbdoc/" + package + "/index.html";
1381 if (Utilities::FileExists(url))
1383 url += "#" + words[1];
1384 mUser->InterpreterUserViewHtmlPage(url);
1388 catch (bbtk::Exception g)
1392 GetExecuter()->ShowRelations(words[1],"0","9999");
1394 catch (bbtk::Exception h){
1395 bbtkError("\""<<words[1].c_str()
1396 <<"\" is not a known command, package, black box type or black box name");
1404 if (words[2]=="all")
1406 if ( words[1]=="packages" )
1408 GetExecuter()->GetFactory()->PrintPackages(true,true);
1413 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1415 catch (bbtk::Exception f)
1421 HelpCommand(words[0]);
1422 bbtkError(words[0]<<" : syntax error");
1427 bbtkError("Should not reach here !!!");
1430 //=======================================================================
1432 //===================================================================
1433 /// Displays the Configuration
1434 void Interpreter::Config() const
1436 ConfigurationFile::GetInstance().GetHelp(1);
1438 //===================================================================
1440 //=======================================================================
1441 /// Displays help on all the commands
1442 void Interpreter::HelpCommands()
1444 std::cout << "Available commands :" << std::endl;
1445 CommandDictType::iterator i;
1446 for ( i = mCommandDict.begin();
1447 i != mCommandDict.end();
1449 std::cout << " " << i->first << std::endl;
1450 // std::cout << " usage : " << i->second.syntax << std::endl;
1451 // std::cout << " " << i->second.help << std::endl;
1455 //=======================================================================
1458 //=======================================================================
1459 /// Displays help on a particular commands
1460 void Interpreter::HelpCommand(const std::string& s)
1462 CommandDictType::iterator c;
1463 c = mCommandDict.find(s);
1464 if ( c == mCommandDict.end() ) {
1465 bbtkError(s<<" : Unknown command");
1467 // std::cout << " " << s << " : "<< std::endl;
1468 // CommandParamDictType::iterator i;
1469 // for ( i = c->second.begin();
1470 // i != c->second.end();
1472 std::cout << " usage : " << c->second.syntax << std::endl;
1473 std::cout << " " << c->second.help << std::endl;
1476 //=======================================================================
1479 //=======================================================================
1480 /// Fills the vector commands with the commands which
1481 /// have the first n chars of buf for prefix
1482 /// TODO : skip initial spaces in buf and also return the position of first
1483 /// non blank char in buf
1484 void Interpreter::FindCommandsWithPrefix( char* buf,
1486 std::vector<std::string>& commands )
1488 CommandDictType::const_iterator i;
1489 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1491 if ((i->first).find(buf,0,n) == 0)
1492 commands.push_back(i->first);
1495 //=======================================================================
1499 //=======================================================================
1500 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1502 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1503 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1505 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1506 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1507 // E.G. STORE THIS IN bbtk_config.xml
1508 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1509 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1510 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1511 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1512 #define BBTK_BACKSPACE_KBCODE 0x00000008
1513 #define BBTK_DEL_KBCODE 0x0000007F
1514 #define BBTK_SPACE_KBCODE 0x00000020
1516 //=======================================================================
1517 void Interpreter::GetLineFromPrompt(std::string& s)
1522 int MAX_LINE_SIZE = 160;
1523 int MAX_HISTORY_SIZE = 100;
1525 char* newline = new char[MAX_LINE_SIZE];
1526 memset(newline,0,MAX_LINE_SIZE);
1527 char* histline = new char[MAX_LINE_SIZE];
1528 memset(histline,0,MAX_LINE_SIZE);
1530 char* line = newline;
1531 int hist = mHistory.size();
1537 read ( STDIN_FILENO, &c, 4) ;
1539 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1541 // Printable character
1542 if ( (ind<MAX_LINE_SIZE-1) &&
1543 ( c >= BBTK_SPACE_KBCODE ) &&
1544 ( c < BBTK_DEL_KBCODE ))
1552 // delete the unused line
1558 // empty lines are not stored in from history
1561 // if history too long : delete oldest command
1562 if (mHistory.size()>MAX_HISTORY_SIZE)
1564 delete mHistory.front();
1565 mHistory.pop_front();
1567 mHistory.push_back(line);
1572 else if ( (ind>0) &&
1573 ((c == BBTK_BACKSPACE_KBCODE) ||
1574 (c == BBTK_DEL_KBCODE)) )
1582 // TODO : Command completion
1583 std::vector<std::string> commands;
1584 FindCommandsWithPrefix( line,ind,commands);
1585 if (commands.size()==1)
1587 std::string com = *commands.begin();
1588 for (; ind<com.size(); ++ind)
1590 PrintChar(com[ind]);
1596 else if (commands.size()>1)
1598 std::vector<std::string>::iterator i;
1600 for (i=commands.begin();i!=commands.end();++i)
1602 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1605 write(STDOUT_FILENO,"\n> ",3);
1606 //for (int j=0;j<ind;++j)
1608 write(STDOUT_FILENO,line,ind);
1612 // Arrow up : back in history
1613 else if (c==BBTK_UP_ARROW_KBCODE)
1617 // erase current line
1618 while (ind--) BackSpace();
1622 strcpy(histline,mHistory[hist]);
1626 write(STDOUT_FILENO,line,ind);
1629 // Arrow down : down in history
1630 else if (c==BBTK_DOWN_ARROW_KBCODE)
1632 if (hist<mHistory.size()-1)
1634 // erase current line
1635 while (ind--) BackSpace();
1639 strcpy(histline,mHistory[hist]);
1643 write(STDOUT_FILENO,line,ind);
1645 // end of history : switch back to newline
1646 else if (hist==mHistory.size()-1)
1648 // erase current line
1649 while (ind--) BackSpace();
1656 write(STDOUT_FILENO,line,ind);
1660 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1662 PrintChar(line[ind]);
1667 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1675 write(STDOUT_FILENO,"\n\r",2);
1683 //=======================================================================
1684 void Interpreter::GetLineFromPrompt(std::string& s)
1710 //=======================================================================
1716 //=======================================================================
1717 void Interpreter::CommandLineInterpreter()
1719 bbtkDebugMessageInc("Interpreter",9,
1720 "Interpreter::CommandLineInterpreter()"<<std::endl);
1722 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1723 // Initialise the tty in non canonical mode with no echo
1724 // oter remembers the previous settings to restore them after
1725 struct termios ter,oter;
1728 ter.c_lflag &= ~ECHO;
1729 ter.c_lflag &= ~ICANON;
1732 tcsetattr(0,TCSANOW,&ter);
1735 mCommandLine = true;
1737 bool insideComment = false; // for multiline comment
1743 GetLineFromPrompt(line);
1744 InterpretLine(line, insideComment);
1746 catch (QuitException e)
1748 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1751 catch (bbtk::Exception e)
1755 catch (std::exception& e)
1757 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1761 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1766 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1767 tcsetattr(0,TCSANOW,&oter);
1770 std::cout << "Good bye !" << std::endl;
1772 bbtkDebugDecTab("Interpreter",9);
1775 //=======================================================================
1776 void Interpreter::Graph(const std::vector<std::string>& words)
1779 bool system_display = true;
1781 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1782 system_display = false;
1784 if (words.size()==1)
1786 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1788 else if (words.size()==2)
1790 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1792 else if (words.size()==3)
1794 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1796 else if (words.size()==4)
1798 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1800 else if (words.size()==5)
1802 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1804 else if (words.size()==6)
1806 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1808 else if (words.size()==7)
1810 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1813 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1814 mUser->InterpreterUserViewHtmlPage(page);
1817 //=======================================================================
1820 //=======================================================================
1821 void Interpreter::Index(const std::string& filename,
1822 const std::string& type)
1824 Factory::IndexEntryType t;
1825 if (type=="Initials") t = Factory::Initials;
1826 else if (type=="Categories") t = Factory::Categories;
1827 else if (type=="Packages") t = Factory::Packages;
1828 else if (type=="Adaptors") t = Factory::Adaptors;
1830 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1832 //=======================================================================