1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/25 15:47:54 $
7 Version: $Revision: 1.54 $
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]);
659 // mExecuter->Remove(words[1]);
663 Utilities::SplitAroundFirstDot(words[1],left,right);
664 Utilities::SplitAroundFirstDot(words[2],left2,right2);
665 mExecuter->Connect(left,right,left2,right2);
669 mExecuter->BeginPackage(words[1]);
673 mExecuter->EndPackage();
677 if (mFileName.size()>0)
679 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
683 mExecuter->Define(words[1],"",filename);
687 mExecuter->Define(words[1],words[2],filename);
692 mExecuter->EndDefine();
696 Print(words[1]); /// \todo use generate command
700 if (words[1]=="freeze")
701 mExecuter->SetNoExecMode(true);
702 else if (words[1]=="unfreeze")
703 mExecuter->SetNoExecMode(false);
705 mExecuter->Update(words[1]);
709 Utilities::SplitAroundFirstDot(words[2],left,right);
710 mExecuter->DefineInput(words[1],left,right,words[3]);
714 Utilities::SplitAroundFirstDot(words[2],left,right);
715 mExecuter->DefineOutput(words[1],left,right,words[3]);
719 Utilities::SplitAroundFirstDot(words[1],left,right);
720 mExecuter->Set(left,right,words[2]);
724 mExecuter->Author(words[1]);
728 mExecuter->Category(words[1]);
733 Index("tmp_index.html");
734 else if (words.size()==2)
736 else if (words.size()==3)
737 Index(words[1],words[2]);
741 mExecuter->Description(words[1]);
751 bbtk::MessageManager::PrintInfo();
755 sscanf(words[2].c_str(),"%d",&level);
756 bbtk::MessageManager::SetMessageLevel(words[1],level);
769 this->mExecuter->Reset();
775 InterpretFile(words[1]);
779 SwitchToFile(words[1]);
781 // if 'source' was given
784 GetExecuter()->SetCurrentFileName(words[1]);
789 GetExecuter()->GetFactory()->LoadPackage(words[1]);
793 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
798 throw QuitException();
802 if (words.size() == 2)
804 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
805 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
809 mExecuter->SetWorkspaceName(words[2]);
814 bbtkInternalError("should not reach here !!!");
817 bbtkDecTab("Interpreter",9);
819 //=======================================================================
825 //=======================================================================
829 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
831 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
833 std::string delimiters = "\"";
834 std::vector<std::string> quote;
835 Utilities::SplitString(str,delimiters,quote);
838 std::vector<std::string>::iterator i;
839 for (i=quote.begin(); i!=quote.end(); )
841 Utilities::SplitString(*i,delimiters,tokens);
845 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
846 tokens.push_back(*i);
851 for (i=tokens.begin(); i!=tokens.end(); ++i)
853 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
855 bbtkDebugMessageCont("Interpreter",9,std::endl);
857 bbtkDebugDecTab("Interpreter",9);
859 //=======================================================================
862 //=======================================================================
863 // Replaces substrings "\\n" by a real carriage return "\n"
864 void SubsBackslashN ( std::string& s )
866 std::string ss("\\n");
867 std::string::size_type pos = 0;
870 while ( pos != std::string::npos )
872 s.replace(pos,2,cr,1);
873 pos = s.find(ss, pos-1);
876 //=======================================================================
879 //=======================================================================
883 void Interpreter::Print( const std::string& str)
885 if (mExecuter->GetNoExecMode()) return;
887 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
890 // InterpretLine ("load std")
891 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
892 // InterpretLine("new Print _P_")
893 // InterpretLine("connect _C_.Out _P_.In")
897 std::vector<std::string> chains;
898 std::string delimiters("$");
900 // Skip delimiters at beginning.
901 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
903 if (lastPos>0) is_text = false;
905 // Find first delimiter.
906 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
908 while (std::string::npos != pos || std::string::npos != lastPos)
912 // Found a text token, add it to the vector.
913 chains.push_back(str.substr(lastPos, pos - lastPos));
914 // std::string token = str.substr(lastPos, pos - lastPos)
915 // InterpretLine("set _C_.In%num% %token%")
921 // is an output (between $$) : decode
922 std::string tok,box,output;
923 tok = str.substr(lastPos, pos - lastPos);
924 Utilities::SplitAroundFirstDot(tok,box,output);
925 chains.push_back( mExecuter->Get(box,output) );
927 // InterpretLine("connect %tok% _C_.In%num%")
930 // Skip delimiters. Note the "not_of"
931 lastPos = str.find_first_not_of(delimiters, pos);
932 // Find next delimiter
933 pos = str.find_first_of(delimiters, lastPos);
938 // InterpretLine("exec _P_")
939 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
941 std::vector<std::string>::iterator i;
942 for (i= chains.begin(); i!=chains.end(); ++i)
944 // bbtkMessage("Echo",1,*i);
948 std::cout << std::endl;
949 bbtkDebugDecTab("Interpreter",9);
952 //=======================================================================
957 // ===================================================================================
959 void Interpreter::SwitchToFile( const std::string& name )
961 // Note : in the following :
962 // name : the user supplied name
963 // - abreviated name e.g. scr scr.bbs
964 // - relative full name e.g. ./scr.bbs ../../scr.bbs
965 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
966 // same for Windows, with c:, d: ...
968 // use ./directory/subdir/scrname.bbs
971 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
972 <<name<<"\")"<<std::endl);
974 std::vector<std::string> script_paths;
975 std::string fullPathScriptName; // full path script name
976 std::string pkgname; // e.g. <scriptname>.bbs
977 std::vector<std::string> Filenames;
979 // The following is *NOT* a debug time message :
980 // It's a user intended message.
981 // Please don't remove it.
982 bbtkMessage("Interpreter",1,
983 "look for : [" << name
984 << "]" << std::endl);
985 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
988 pkgname = Utilities::ExtractScriptName(name,upath);
990 bbtkMessage("Interpreter",1,
991 "extract : pkgname [" << pkgname
992 << "] upath [" << upath << "]" << std::endl);
993 bool fullnameGiven = false;
994 bool foundFile = false;
996 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
1000 std::stringstream* stream = new std::stringstream;
1001 //if (upath.size()!=0) // avoid troubles for "*"
1003 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
1005 int nbFiles = Utilities::Explore(upath, false, Filenames);
1007 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1009 int lgr = (*i).size();
1011 continue; // ignore non .bbs file
1012 if ((*i).substr(lgr-4, 4) != ".bbs")
1015 printf("EED Interpreter::SwitchToFile flag01 %s \n", (*i).c_str() );
1016 (*stream) << "include \"" << *i << "\"\n";
1021 bbtkMessage("Interpreter",2,
1022 "WARNING : No '.bbs' file found in ["
1023 << upath << "]" << std::endl);
1025 SwitchToStream(stream);
1031 std::vector<std::string>::iterator i;
1032 std::string fullDirectoryName;
1033 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1037 // we *really* want '.' to be the current working directory
1039 char buf[2048]; // for getcwd
1040 char * currentDir = getcwd(buf, 2048);
1041 std::string cwd(currentDir);
1045 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
1047 // without last slash "\"
1048 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
1050 // Check if library exists
1051 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
1053 // The following is *NOT* a debug time message :
1054 // It's a user intended message.
1055 // Please don't remove it.
1056 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
1057 <<"] : doesn't exist" <<std::endl);
1058 continue; // try next path
1063 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
1066 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1068 int lgr = (*i).size();
1070 continue; // ignore non .bbs file
1071 if ((*i).substr(lgr-4, 4) != ".bbs")
1074 printf("EED Interpreter::SwitchToFile flag02 %s \n", (*i).c_str() );
1075 (*stream) << "include \"" << *i << "\"\n";
1080 bbtkMessage("Interpreter",1,
1081 "WARNING : No '.bbs' file found in ["
1082 << fullDirectoryName << "]" << std::endl);
1084 SwitchToStream(stream);
1087 //break; // a directory was found; we stop iterating
1088 // LG : No! We want all files included !
1093 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1094 // (not only a plain script name)
1095 // we trust him, and try to expland the directory name
1096 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1098 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1101 // ===========================================================check user supplied location
1102 fullnameGiven = true;
1104 fullPathScriptName = Utilities::ExpandLibName(name, false);
1106 // allow user to always forget ".bbs"
1107 int l = fullPathScriptName.size();
1113 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1115 fullPathScriptName = fullPathScriptName + ".bbs";
1120 fullPathScriptName = fullPathScriptName + ".bbs";
1123 if ( Utilities::FileExists(fullPathScriptName))
1130 // =============================================================== iterate on the paths
1133 std::vector<std::string>::iterator i;
1134 for (i=script_paths.begin();i!=script_paths.end();++i)
1137 // we *really* want '.' to be the current working directory
1139 char buf[2048]; // for getcwd
1140 char * currentDir = getcwd(buf, 2048);
1141 std::string cwd(currentDir);
1145 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1147 // Check if library exists
1148 if ( ! Utilities::FileExists(fullPathScriptName) )
1150 // The following is *NOT* a debug time message :
1151 // It's a user intended message.
1152 // Please don't remove it.
1153 bbtkMessage("Interpreter",2,
1154 " [" <<fullPathScriptName <<"] : doesn't exist"
1156 continue; // try next path
1158 bbtkMessage("Interpreter",2,
1159 " [" <<fullPathScriptName
1160 <<"] : found" <<std::endl);
1162 break; // a script was found; we stop iterating
1164 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1170 if(fullPathScriptName == "")
1171 bbtkError("Path ["<<upath<<"] doesn't exist");
1173 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1175 bbtkError("No ["<<pkgname<<".bbs] script found");
1179 LoadScript(fullPathScriptName,name);
1185 void Interpreter::SwitchToStream( std::stringstream* stream )
1187 mFile.push_back(stream);
1188 std::ostringstream buffer_name;
1190 buffer_name << "buffer_" ;
1192 if (mFileName.size()>0 )
1194 buffer_name << mFileName.back() << "_" << mLine.back();
1196 mFileName.push_back(buffer_name.str());
1197 mIncludeFileName.push_back(buffer_name.str());
1201 //=======================================================================
1203 void Interpreter::LoadScript( std::string fullPathScriptName,
1204 std::string includeScriptName)
1206 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1208 bool okScriptExist=false;
1209 int iStrScript,sizeVecStricpt=mFileName.size();
1210 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1212 if (mFileName[iStrScript] == fullPathScriptName )
1218 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1219 // if (okScriptExist==true)
1221 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1222 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1227 s = new std::ifstream;
1228 s->open(fullPathScriptName.c_str());
1231 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1235 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1236 << "] found" << std::endl);
1239 mFileName.push_back(fullPathScriptName);
1240 mIncludeFileName.push_back(includeScriptName);
1246 //=======================================================================
1250 void Interpreter::CloseCurrentFile()
1252 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1255 if (mFile.size()==0)
1257 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1261 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1263 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1264 if (file!=0) file->close();
1266 delete mFile.back();
1268 mFileName.pop_back();
1269 mIncludeFileName.pop_back();
1272 bbtkDebugMessage("Interpreter",9," Remains "
1274 <<" open"<<std::endl);
1275 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1278 //=======================================================================
1280 //=======================================================================
1284 void Interpreter::CloseAllFiles()
1286 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1289 while (mFile.size() != 0)
1293 mFile.back()->close();
1294 delete mFile.back();
1296 bbtkDebugMessage("Interpreter",9,
1297 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1298 mFileName.pop_back();
1299 mIncludeFileName.pop_back();
1303 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1306 //=======================================================================
1310 //=======================================================================
1314 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1315 CommandInfoType& info )
1317 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1319 // searches the command category
1320 CommandDictType::iterator c;
1321 c = mCommandDict.find(words[0]);
1322 if ( c == mCommandDict.end() ) {
1323 bbtkError(words[0]<<" : unknown command");
1326 // tests the number of args
1327 if ( ( words.size()-1 < c->second.argmin ) ||
1328 ( words.size()-1 > c->second.argmax ) )
1330 HelpCommand(words[0]);
1331 bbtkError(words[0]<<" : wrong number of arguments");
1335 bbtkDecTab("Interpreter",9);
1337 //=======================================================================
1340 //=======================================================================
1341 /// Displays help on all the commands
1342 void Interpreter::Help(const std::vector<std::string>& words)
1344 unsigned int nbarg = words.size()-1;
1352 if (words[1]=="packages")
1354 GetExecuter()->GetFactory()->PrintPackages(true);
1359 HelpCommand(words[1]);
1361 catch (bbtk::Exception e)
1365 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1369 ConfigurationFile::GetInstance().Get_doc_path();
1370 url += "/bbdoc/" + words[1] + "/index.html";
1371 if (Utilities::FileExists(url))
1373 mUser->InterpreterUserViewHtmlPage(url);
1377 catch (bbtk::Exception f)
1381 std::string package;
1382 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1386 ConfigurationFile::GetInstance().Get_doc_path();
1387 url += "/bbdoc/" + package + "/index.html";
1388 if (Utilities::FileExists(url))
1390 url += "#" + words[1];
1391 mUser->InterpreterUserViewHtmlPage(url);
1395 catch (bbtk::Exception g)
1399 GetExecuter()->ShowRelations(words[1],"0","9999");
1401 catch (bbtk::Exception h){
1402 bbtkError("\""<<words[1].c_str()
1403 <<"\" is not a known command, package, black box type or black box name");
1411 if (words[2]=="all")
1413 if ( words[1]=="packages" )
1415 GetExecuter()->GetFactory()->PrintPackages(true,true);
1420 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1422 catch (bbtk::Exception f)
1428 HelpCommand(words[0]);
1429 bbtkError(words[0]<<" : syntax error");
1434 bbtkError("Should not reach here !!!");
1437 //=======================================================================
1439 //===================================================================
1440 /// Displays the Configuration
1441 void Interpreter::Config() const
1443 ConfigurationFile::GetInstance().GetHelp(1);
1445 //===================================================================
1447 //=======================================================================
1448 /// Displays help on all the commands
1449 void Interpreter::HelpCommands()
1451 std::cout << "Available commands :" << std::endl;
1452 CommandDictType::iterator i;
1453 for ( i = mCommandDict.begin();
1454 i != mCommandDict.end();
1456 std::cout << " " << i->first << std::endl;
1457 // std::cout << " usage : " << i->second.syntax << std::endl;
1458 // std::cout << " " << i->second.help << std::endl;
1462 //=======================================================================
1465 //=======================================================================
1466 /// Displays help on a particular commands
1467 void Interpreter::HelpCommand(const std::string& s)
1469 CommandDictType::iterator c;
1470 c = mCommandDict.find(s);
1471 if ( c == mCommandDict.end() ) {
1472 bbtkError(s<<" : Unknown command");
1474 // std::cout << " " << s << " : "<< std::endl;
1475 // CommandParamDictType::iterator i;
1476 // for ( i = c->second.begin();
1477 // i != c->second.end();
1479 std::cout << " usage : " << c->second.syntax << std::endl;
1480 std::cout << " " << c->second.help << std::endl;
1483 //=======================================================================
1486 //=======================================================================
1487 /// Fills the vector commands with the commands which
1488 /// have the first n chars of buf for prefix
1489 /// TODO : skip initial spaces in buf and also return the position of first
1490 /// non blank char in buf
1491 void Interpreter::FindCommandsWithPrefix( char* buf,
1493 std::vector<std::string>& commands )
1495 CommandDictType::const_iterator i;
1496 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1498 if ((i->first).find(buf,0,n) == 0)
1499 commands.push_back(i->first);
1502 //=======================================================================
1506 //=======================================================================
1507 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1509 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1510 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1512 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1513 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1514 // E.G. STORE THIS IN bbtk_config.xml
1515 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1516 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1517 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1518 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1519 #define BBTK_BACKSPACE_KBCODE 0x00000008
1520 #define BBTK_DEL_KBCODE 0x0000007F
1521 #define BBTK_SPACE_KBCODE 0x00000020
1523 //=======================================================================
1524 void Interpreter::GetLineFromPrompt(std::string& s)
1529 int MAX_LINE_SIZE = 160;
1530 int MAX_HISTORY_SIZE = 100;
1532 char* newline = new char[MAX_LINE_SIZE];
1533 memset(newline,0,MAX_LINE_SIZE);
1534 char* histline = new char[MAX_LINE_SIZE];
1535 memset(histline,0,MAX_LINE_SIZE);
1537 char* line = newline;
1538 int hist = mHistory.size();
1544 read ( STDIN_FILENO, &c, 4) ;
1546 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1548 // Printable character
1549 if ( (ind<MAX_LINE_SIZE-1) &&
1550 ( c >= BBTK_SPACE_KBCODE ) &&
1551 ( c < BBTK_DEL_KBCODE ))
1559 // delete the unused line
1565 // empty lines are not stored in from history
1568 // if history too long : delete oldest command
1569 if (mHistory.size()>MAX_HISTORY_SIZE)
1571 delete mHistory.front();
1572 mHistory.pop_front();
1574 mHistory.push_back(line);
1579 else if ( (ind>0) &&
1580 ((c == BBTK_BACKSPACE_KBCODE) ||
1581 (c == BBTK_DEL_KBCODE)) )
1589 // TODO : Command completion
1590 std::vector<std::string> commands;
1591 FindCommandsWithPrefix( line,ind,commands);
1592 if (commands.size()==1)
1594 std::string com = *commands.begin();
1595 for (; ind<com.size(); ++ind)
1597 PrintChar(com[ind]);
1603 else if (commands.size()>1)
1605 std::vector<std::string>::iterator i;
1607 for (i=commands.begin();i!=commands.end();++i)
1609 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1612 write(STDOUT_FILENO,"\n> ",3);
1613 //for (int j=0;j<ind;++j)
1615 write(STDOUT_FILENO,line,ind);
1619 // Arrow up : back in history
1620 else if (c==BBTK_UP_ARROW_KBCODE)
1624 // erase current line
1625 while (ind--) BackSpace();
1629 strcpy(histline,mHistory[hist]);
1633 write(STDOUT_FILENO,line,ind);
1636 // Arrow down : down in history
1637 else if (c==BBTK_DOWN_ARROW_KBCODE)
1639 if (hist<mHistory.size()-1)
1641 // erase current line
1642 while (ind--) BackSpace();
1646 strcpy(histline,mHistory[hist]);
1650 write(STDOUT_FILENO,line,ind);
1652 // end of history : switch back to newline
1653 else if (hist==mHistory.size()-1)
1655 // erase current line
1656 while (ind--) BackSpace();
1663 write(STDOUT_FILENO,line,ind);
1667 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1669 PrintChar(line[ind]);
1674 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1682 write(STDOUT_FILENO,"\n\r",2);
1690 //=======================================================================
1691 void Interpreter::GetLineFromPrompt(std::string& s)
1717 //=======================================================================
1723 //=======================================================================
1724 void Interpreter::CommandLineInterpreter()
1726 bbtkDebugMessageInc("Interpreter",9,
1727 "Interpreter::CommandLineInterpreter()"<<std::endl);
1729 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1730 // Initialise the tty in non canonical mode with no echo
1731 // oter remembers the previous settings to restore them after
1732 struct termios ter,oter;
1735 ter.c_lflag &= ~ECHO;
1736 ter.c_lflag &= ~ICANON;
1739 tcsetattr(0,TCSANOW,&ter);
1742 mCommandLine = true;
1744 bool insideComment = false; // for multiline comment
1750 GetLineFromPrompt(line);
1751 InterpretLine(line, insideComment);
1753 catch (QuitException e)
1755 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1758 catch (bbtk::Exception e)
1762 catch (std::exception& e)
1764 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1768 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1773 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1774 tcsetattr(0,TCSANOW,&oter);
1777 std::cout << "Good bye !" << std::endl;
1779 bbtkDebugDecTab("Interpreter",9);
1782 //=======================================================================
1783 void Interpreter::Graph(const std::vector<std::string>& words)
1786 bool system_display = true;
1788 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1789 system_display = false;
1791 if (words.size()==1)
1793 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1795 else if (words.size()==2)
1797 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1799 else if (words.size()==3)
1801 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1803 else if (words.size()==4)
1805 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1807 else if (words.size()==5)
1809 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1811 else if (words.size()==6)
1813 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1815 else if (words.size()==7)
1817 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1820 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1821 mUser->InterpreterUserViewHtmlPage(page);
1824 //=======================================================================
1827 //=======================================================================
1828 void Interpreter::Index(const std::string& filename,
1829 const std::string& type)
1831 Factory::IndexEntryType t;
1832 if (type=="Initials") t = Factory::Initials;
1833 else if (type=="Categories") t = Factory::Categories;
1834 else if (type=="Packages") t = Factory::Packages;
1835 else if (type=="Adaptors") t = Factory::Adaptors;
1837 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1839 //=======================================================================