1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/21 11:44:37 $
7 Version: $Revision: 1.51 $
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 //=======================================================================
303 Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
305 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
307 bool exm = mCommandLine;
308 mCommandLine = false;
310 ExitStatus status = Interpreter_OK;
315 SwitchToFile(filename);
317 bool insideComment = false; // for multiline comment
318 while (mFile.size()>0)
320 while (!mFile.back()->eof()) {
323 mFile.back()->getline(buf,500);
324 std::string str(buf);
325 int size=str.length();
326 if ( str[ size-1 ]==13 )
331 InterpretLine(str, insideComment);
337 catch (QuitException e)
339 status = Interpreter_QUIT;
340 if (mThrow) throw QuitException();
342 catch (bbtk::Exception e)
344 std::stringstream mess;
345 mess << "* ERROR : "<<e.GetMessage()<<std::endl;
346 if (mFileName.size()) {
347 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
348 mess << "* LINE : "<<mLine.back()<<std::endl;
350 status = Interpreter_ERROR;
352 throw bbtk::Exception("Interpreter","",mess.str());
354 std::cerr << mess.str();
357 catch (std::exception& e)
359 std::stringstream mess;
360 mess << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
361 if (mFileName.size()) {
362 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
363 mess << "* LINE : "<<mLine.back()<<std::endl;
365 status = Interpreter_ERROR;
367 throw bbtk::Exception("Interpreter","",mess.str());
369 std::cerr << mess.str();
373 std::stringstream mess;
374 mess << "* UNDEFINED ERROR (not a bbtk nor a std exception)"
376 if (mFileName.size()) {
377 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
378 mess << "* LINE : "<<mLine.back()<<std::endl;
380 status = Interpreter_ERROR;
382 throw bbtk::Exception("Interpreter","",mess.str());
384 std::cerr << mess.str();
388 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
389 bbtkDecTab("Interpreter",9);
395 //=======================================================================
398 //=======================================================================
402 Interpreter::ExitStatus
403 Interpreter::InterpretBuffer( std::stringstream* buffer )
405 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
407 bool exm = mCommandLine;
408 mCommandLine = false;
410 ExitStatus status = Interpreter_OK;
414 SwitchToStream(buffer);
415 bool insideComment = false; // for multiline comment
416 while (mFile.size()>0)
418 while (!mFile.back()->eof()) {
421 mFile.back()->getline(buf,500);
422 std::string str(buf);
424 int size=str.length();
425 if ( str[ size-1 ]==13 )
430 InterpretLine(str, insideComment);
437 catch (QuitException e)
439 status = Interpreter_QUIT;
441 catch (bbtk::Exception e)
443 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
444 if (mFileName.size())
446 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
447 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
449 status = Interpreter_ERROR;
451 catch (std::exception& e)
453 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
454 if (mFileName.size())
456 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
457 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
459 status = Interpreter_ERROR;
464 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
465 if (mFileName.size())
467 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
468 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
470 status = Interpreter_ERROR;
474 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
475 bbtkDecTab("Interpreter",9);
480 //=======================================================================
482 //=======================================================================
483 /// Runs the interpretation of a command
484 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
486 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
488 ExitStatus status = Interpreter_OK;
492 bool insideComment = false;
493 InterpretLine(line, insideComment);
495 catch (QuitException e)
497 status = Interpreter_QUIT;
499 catch (bbtk::Exception e)
501 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
502 status = Interpreter_ERROR;
504 catch (std::exception& e)
506 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
507 status = Interpreter_ERROR;
512 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
513 status = Interpreter_ERROR;
517 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
519 bbtkDecTab("Interpreter",9);
525 //=======================================================================
529 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
531 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
532 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
534 std::vector<std::string> words;
535 SplitLine(line,words);
540 bbtkDebugDecTab("Interpreter",9);
544 // Single line comment : # or //
545 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
547 bbtkDebugDecTab("Interpreter",9);
548 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
552 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
554 if (words[0][0]=='/' && words[0][1]=='*')
556 bbtkDebugDecTab("Interpreter",9);
557 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
558 insideComment = true;
562 if (words[0][0]=='*' && words[0][1]=='/')
564 bbtkDebugDecTab("Interpreter",9);
565 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
566 if ( !insideComment ) {
567 bbtkDebugDecTab("Interpreter",9);
568 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
570 insideComment = false;
576 bbtkDebugDecTab("Interpreter",9);
577 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
582 CommandInfoType command;
583 InterpretCommand(words,command);
585 bbtkDebugMessage("Interpreter",9,
586 "Command='"<<command.category
587 <<"' code="<<command.code<<std::endl);
589 std::string left,right,left2,right2;
590 std::string filename;
591 switch (command.code)
594 mExecuter->Create(words[1],words[2]);
599 // mExecuter->Remove(words[1]);
603 Utilities::SplitAroundFirstDot(words[1],left,right);
604 Utilities::SplitAroundFirstDot(words[2],left2,right2);
605 mExecuter->Connect(left,right,left2,right2);
609 mExecuter->BeginPackage(words[1]);
613 mExecuter->EndPackage();
617 if (mFileName.size()>0)
619 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
623 mExecuter->Define(words[1],"",filename);
627 mExecuter->Define(words[1],words[2],filename);
632 mExecuter->EndDefine();
636 Print(words[1]); /// \todo use generate command
640 if (words[1]=="freeze")
641 mExecuter->SetNoExecMode(true);
642 else if (words[1]=="unfreeze")
643 mExecuter->SetNoExecMode(false);
645 mExecuter->Update(words[1]);
649 Utilities::SplitAroundFirstDot(words[2],left,right);
650 mExecuter->DefineInput(words[1],left,right,words[3]);
654 Utilities::SplitAroundFirstDot(words[2],left,right);
655 mExecuter->DefineOutput(words[1],left,right,words[3]);
659 Utilities::SplitAroundFirstDot(words[1],left,right);
660 mExecuter->Set(left,right,words[2]);
664 mExecuter->Author(words[1]);
668 mExecuter->Category(words[1]);
673 Index("tmp_index.html");
674 else if (words.size()==2)
676 else if (words.size()==3)
677 Index(words[1],words[2]);
681 mExecuter->Description(words[1]);
691 bbtk::MessageManager::PrintInfo();
695 sscanf(words[2].c_str(),"%d",&level);
696 bbtk::MessageManager::SetMessageLevel(words[1],level);
709 this->mExecuter->Reset();
715 InterpretFile(words[1]);
719 SwitchToFile(words[1]);
721 // if 'source' was given
724 GetExecuter()->SetCurrentFileName(words[1]);
729 GetExecuter()->GetFactory()->LoadPackage(words[1]);
733 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
738 throw QuitException();
742 if (words.size() == 2)
744 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
745 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
749 mExecuter->SetWorkspaceName(words[2]);
754 bbtkInternalError("should not reach here !!!");
757 bbtkDecTab("Interpreter",9);
759 //=======================================================================
765 //=======================================================================
769 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
771 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
773 std::string delimiters = "\"";
774 std::vector<std::string> quote;
775 Utilities::SplitString(str,delimiters,quote);
778 std::vector<std::string>::iterator i;
779 for (i=quote.begin(); i!=quote.end(); )
781 Utilities::SplitString(*i,delimiters,tokens);
785 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
786 tokens.push_back(*i);
791 for (i=tokens.begin(); i!=tokens.end(); ++i)
793 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
795 bbtkDebugMessageCont("Interpreter",9,std::endl);
797 bbtkDebugDecTab("Interpreter",9);
799 //=======================================================================
802 //=======================================================================
803 // Replaces substrings "\\n" by a real carriage return "\n"
804 void SubsBackslashN ( std::string& s )
806 std::string ss("\\n");
807 std::string::size_type pos = 0;
810 while ( pos != std::string::npos )
812 s.replace(pos,2,cr,1);
813 pos = s.find(ss, pos-1);
816 //=======================================================================
819 //=======================================================================
823 void Interpreter::Print( const std::string& str)
825 if (mExecuter->GetNoExecMode()) return;
827 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
830 // InterpretLine ("load std")
831 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
832 // InterpretLine("new Print _P_")
833 // InterpretLine("connect _C_.Out _P_.In")
837 std::vector<std::string> chains;
838 std::string delimiters("$");
840 // Skip delimiters at beginning.
841 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
843 if (lastPos>0) is_text = false;
845 // Find first delimiter.
846 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
848 while (std::string::npos != pos || std::string::npos != lastPos)
852 // Found a text token, add it to the vector.
853 chains.push_back(str.substr(lastPos, pos - lastPos));
854 // std::string token = str.substr(lastPos, pos - lastPos)
855 // InterpretLine("set _C_.In%num% %token%")
861 // is an output (between $$) : decode
862 std::string tok,box,output;
863 tok = str.substr(lastPos, pos - lastPos);
864 Utilities::SplitAroundFirstDot(tok,box,output);
865 chains.push_back( mExecuter->Get(box,output) );
867 // InterpretLine("connect %tok% _C_.In%num%")
870 // Skip delimiters. Note the "not_of"
871 lastPos = str.find_first_not_of(delimiters, pos);
872 // Find next delimiter
873 pos = str.find_first_of(delimiters, lastPos);
878 // InterpretLine("exec _P_")
879 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
881 std::vector<std::string>::iterator i;
882 for (i= chains.begin(); i!=chains.end(); ++i)
884 // bbtkMessage("Echo",1,*i);
888 std::cout << std::endl;
889 bbtkDebugDecTab("Interpreter",9);
892 //=======================================================================
897 // ===================================================================================
899 void Interpreter::SwitchToFile( const std::string& name )
901 // Note : in the following :
902 // name : the user supplied name
903 // - abreviated name e.g. scr scr.bbs
904 // - relative full name e.g. ./scr.bbs ../../scr.bbs
905 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
906 // same for Windows, with c:, d: ...
908 // use ./directory/subdir/scrname.bbs
911 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
912 <<name<<"\")"<<std::endl);
914 std::vector<std::string> script_paths;
915 std::string fullPathScriptName; // full path script name
916 std::string pkgname; // e.g. <scriptname>.bbs
917 std::vector<std::string> Filenames;
919 // The following is *NOT* a debug time message :
920 // It's a user intended message.
921 // Please don't remove it.
922 bbtkMessage("Interpreter",1,
923 "look for : [" << name
924 << "]" << std::endl);
925 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
928 pkgname = Utilities::ExtractScriptName(name,upath);
930 bbtkMessage("Interpreter",1,
931 "extract : pkgname [" << pkgname
932 << "] upath [" << upath << "]" << std::endl);
933 bool fullnameGiven = false;
934 bool foundFile = false;
936 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
940 std::stringstream* stream = new std::stringstream;
941 //if (upath.size()!=0) // avoid troubles for "*"
943 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
945 int nbFiles = Utilities::Explore(upath, false, Filenames);
947 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
949 int lgr = (*i).size();
951 continue; // ignore non .bbs file
952 if ((*i).substr(lgr-4, 4) != ".bbs")
955 (*stream) << "include " << *i << "\n";
960 bbtkMessage("Interpreter",2,
961 "WARNING : No '.bbs' file found in ["
962 << upath << "]" << std::endl);
964 SwitchToStream(stream);
970 std::vector<std::string>::iterator i;
971 std::string fullDirectoryName;
972 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
976 // we *really* want '.' to be the current working directory
978 char buf[2048]; // for getcwd
979 char * currentDir = getcwd(buf, 2048);
980 std::string cwd(currentDir);
984 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
986 // without last slash "\"
987 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
989 // Check if library exists
990 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
992 // The following is *NOT* a debug time message :
993 // It's a user intended message.
994 // Please don't remove it.
995 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
996 <<"] : doesn't exist" <<std::endl);
997 continue; // try next path
1002 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
1005 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1007 int lgr = (*i).size();
1009 continue; // ignore non .bbs file
1010 if ((*i).substr(lgr-4, 4) != ".bbs")
1013 (*stream) << "include " << *i << "\n";
1017 bbtkMessage("Interpreter",1,
1018 "WARNING : No '.bbs' file found in ["
1019 << fullDirectoryName << "]" << std::endl);
1021 SwitchToStream(stream);
1024 //break; // a directory was found; we stop iterating
1025 // LG : No! We want all files included !
1030 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1031 // (not only a plain script name)
1032 // we trust him, and try to expland the directory name
1033 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1035 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1038 // ===========================================================check user supplied location
1039 fullnameGiven = true;
1041 fullPathScriptName = Utilities::ExpandLibName(name, false);
1043 // allow user to always forget ".bbs"
1044 int l = fullPathScriptName.size();
1050 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1052 fullPathScriptName = fullPathScriptName + ".bbs";
1057 fullPathScriptName = fullPathScriptName + ".bbs";
1060 if ( Utilities::FileExists(fullPathScriptName))
1067 // =============================================================== iterate on the paths
1070 std::vector<std::string>::iterator i;
1071 for (i=script_paths.begin();i!=script_paths.end();++i)
1074 // we *really* want '.' to be the current working directory
1076 char buf[2048]; // for getcwd
1077 char * currentDir = getcwd(buf, 2048);
1078 std::string cwd(currentDir);
1082 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1084 // Check if library exists
1085 if ( ! Utilities::FileExists(fullPathScriptName) )
1087 // The following is *NOT* a debug time message :
1088 // It's a user intended message.
1089 // Please don't remove it.
1090 bbtkMessage("Interpreter",2,
1091 " [" <<fullPathScriptName <<"] : doesn't exist"
1093 continue; // try next path
1095 bbtkMessage("Interpreter",2,
1096 " [" <<fullPathScriptName
1097 <<"] : found" <<std::endl);
1099 break; // a script was found; we stop iterating
1101 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1107 if(fullPathScriptName == "")
1108 bbtkError("Path ["<<upath<<"] doesn't exist");
1110 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1112 bbtkError("No ["<<pkgname<<".bbs] script found");
1116 LoadScript(fullPathScriptName,name);
1122 void Interpreter::SwitchToStream( std::stringstream* stream )
1124 mFile.push_back(stream);
1125 std::ostringstream buffer_name;
1127 buffer_name << "buffer_" ;
1129 if (mFileName.size()>0 )
1131 buffer_name << mFileName.back() << "_" << mLine.back();
1133 mFileName.push_back(buffer_name.str());
1134 mIncludeFileName.push_back(buffer_name.str());
1138 //=======================================================================
1140 void Interpreter::LoadScript( std::string fullPathScriptName,
1141 std::string includeScriptName)
1143 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1145 bool okScriptExist=false;
1146 int iStrScript,sizeVecStricpt=mFileName.size();
1147 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1149 if (mFileName[iStrScript] == fullPathScriptName )
1155 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1156 // if (okScriptExist==true)
1158 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1159 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1164 s = new std::ifstream;
1165 s->open(fullPathScriptName.c_str());
1168 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1172 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1173 << "] found" << std::endl);
1176 mFileName.push_back(fullPathScriptName);
1177 mIncludeFileName.push_back(includeScriptName);
1182 //=======================================================================
1186 void Interpreter::CloseCurrentFile()
1188 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1191 if (mFile.size()==0)
1193 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1197 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1199 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1200 if (file!=0) file->close();
1202 delete mFile.back();
1204 mFileName.pop_back();
1205 mIncludeFileName.pop_back();
1208 bbtkDebugMessage("Interpreter",9," Remains "
1210 <<" open"<<std::endl);
1211 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1214 //=======================================================================
1216 //=======================================================================
1220 void Interpreter::CloseAllFiles()
1222 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1225 while (mFile.size() != 0)
1229 mFile.back()->close();
1230 delete mFile.back();
1232 bbtkDebugMessage("Interpreter",9,
1233 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1234 mFileName.pop_back();
1235 mIncludeFileName.pop_back();
1239 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1242 //=======================================================================
1246 //=======================================================================
1250 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1251 CommandInfoType& info )
1253 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1255 // searches the command category
1256 CommandDictType::iterator c;
1257 c = mCommandDict.find(words[0]);
1258 if ( c == mCommandDict.end() ) {
1259 bbtkError(words[0]<<" : unknown command");
1262 // tests the number of args
1263 if ( ( words.size()-1 < c->second.argmin ) ||
1264 ( words.size()-1 > c->second.argmax ) )
1266 HelpCommand(words[0]);
1267 bbtkError(words[0]<<" : wrong number of arguments");
1271 bbtkDecTab("Interpreter",9);
1273 //=======================================================================
1276 //=======================================================================
1277 /// Displays help on all the commands
1278 void Interpreter::Help(const std::vector<std::string>& words)
1280 unsigned int nbarg = words.size()-1;
1288 if (words[1]=="packages")
1290 GetExecuter()->GetFactory()->PrintPackages(true);
1295 HelpCommand(words[1]);
1297 catch (bbtk::Exception e)
1301 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1305 ConfigurationFile::GetInstance().Get_doc_path();
1306 url += "/bbdoc/" + words[1] + "/index.html";
1307 if (Utilities::FileExists(url))
1309 mUser->InterpreterUserViewHtmlPage(url);
1313 catch (bbtk::Exception f)
1317 std::string package;
1318 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1322 ConfigurationFile::GetInstance().Get_doc_path();
1323 url += "/bbdoc/" + package + "/index.html";
1324 if (Utilities::FileExists(url))
1326 url += "#" + words[1];
1327 mUser->InterpreterUserViewHtmlPage(url);
1331 catch (bbtk::Exception g)
1335 GetExecuter()->ShowRelations(words[1],"0","9999");
1337 catch (bbtk::Exception h){
1338 bbtkError("\""<<words[1].c_str()
1339 <<"\" is not a known command, package, black box type or black box name");
1347 if (words[2]=="all")
1349 if ( words[1]=="packages" )
1351 GetExecuter()->GetFactory()->PrintPackages(true,true);
1356 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1358 catch (bbtk::Exception f)
1364 HelpCommand(words[0]);
1365 bbtkError(words[0]<<" : syntax error");
1370 bbtkError("Should not reach here !!!");
1373 //=======================================================================
1375 //===================================================================
1376 /// Displays the Configuration
1377 void Interpreter::Config() const
1379 ConfigurationFile::GetInstance().GetHelp(1);
1381 //===================================================================
1383 //=======================================================================
1384 /// Displays help on all the commands
1385 void Interpreter::HelpCommands()
1387 std::cout << "Available commands :" << std::endl;
1388 CommandDictType::iterator i;
1389 for ( i = mCommandDict.begin();
1390 i != mCommandDict.end();
1392 std::cout << " " << i->first << std::endl;
1393 // std::cout << " usage : " << i->second.syntax << std::endl;
1394 // std::cout << " " << i->second.help << std::endl;
1398 //=======================================================================
1401 //=======================================================================
1402 /// Displays help on a particular commands
1403 void Interpreter::HelpCommand(const std::string& s)
1405 CommandDictType::iterator c;
1406 c = mCommandDict.find(s);
1407 if ( c == mCommandDict.end() ) {
1408 bbtkError(s<<" : Unknown command");
1410 // std::cout << " " << s << " : "<< std::endl;
1411 // CommandParamDictType::iterator i;
1412 // for ( i = c->second.begin();
1413 // i != c->second.end();
1415 std::cout << " usage : " << c->second.syntax << std::endl;
1416 std::cout << " " << c->second.help << std::endl;
1419 //=======================================================================
1422 //=======================================================================
1423 /// Fills the vector commands with the commands which
1424 /// have the first n chars of buf for prefix
1425 /// TODO : skip initial spaces in buf and also return the position of first
1426 /// non blank char in buf
1427 void Interpreter::FindCommandsWithPrefix( char* buf,
1429 std::vector<std::string>& commands )
1431 CommandDictType::const_iterator i;
1432 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1434 if ((i->first).find(buf,0,n) == 0)
1435 commands.push_back(i->first);
1438 //=======================================================================
1442 //=======================================================================
1443 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1445 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1446 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1448 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1449 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1450 // E.G. STORE THIS IN bbtk_config.xml
1451 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1452 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1453 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1454 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1455 #define BBTK_BACKSPACE_KBCODE 0x00000008
1456 #define BBTK_DEL_KBCODE 0x0000007F
1457 #define BBTK_SPACE_KBCODE 0x00000020
1459 //=======================================================================
1460 void Interpreter::GetLineFromPrompt(std::string& s)
1465 int MAX_LINE_SIZE = 160;
1466 int MAX_HISTORY_SIZE = 100;
1468 char* newline = new char[MAX_LINE_SIZE];
1469 memset(newline,0,MAX_LINE_SIZE);
1470 char* histline = new char[MAX_LINE_SIZE];
1471 memset(histline,0,MAX_LINE_SIZE);
1473 char* line = newline;
1474 int hist = mHistory.size();
1480 read ( STDIN_FILENO, &c, 4) ;
1482 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1484 // Printable character
1485 if ( (ind<MAX_LINE_SIZE-1) &&
1486 ( c >= BBTK_SPACE_KBCODE ) &&
1487 ( c < BBTK_DEL_KBCODE ))
1495 // delete the unused line
1501 // empty lines are not stored in from history
1504 // if history too long : delete oldest command
1505 if (mHistory.size()>MAX_HISTORY_SIZE)
1507 delete mHistory.front();
1508 mHistory.pop_front();
1510 mHistory.push_back(line);
1515 else if ( (ind>0) &&
1516 ((c == BBTK_BACKSPACE_KBCODE) ||
1517 (c == BBTK_DEL_KBCODE)) )
1525 // TODO : Command completion
1526 std::vector<std::string> commands;
1527 FindCommandsWithPrefix( line,ind,commands);
1528 if (commands.size()==1)
1530 std::string com = *commands.begin();
1531 for (; ind<com.size(); ++ind)
1533 PrintChar(com[ind]);
1539 else if (commands.size()>1)
1541 std::vector<std::string>::iterator i;
1543 for (i=commands.begin();i!=commands.end();++i)
1545 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1548 write(STDOUT_FILENO,"\n> ",3);
1549 //for (int j=0;j<ind;++j)
1551 write(STDOUT_FILENO,line,ind);
1555 // Arrow up : back in history
1556 else if (c==BBTK_UP_ARROW_KBCODE)
1560 // erase current line
1561 while (ind--) BackSpace();
1565 strcpy(histline,mHistory[hist]);
1569 write(STDOUT_FILENO,line,ind);
1572 // Arrow down : down in history
1573 else if (c==BBTK_DOWN_ARROW_KBCODE)
1575 if (hist<mHistory.size()-1)
1577 // erase current line
1578 while (ind--) BackSpace();
1582 strcpy(histline,mHistory[hist]);
1586 write(STDOUT_FILENO,line,ind);
1588 // end of history : switch back to newline
1589 else if (hist==mHistory.size()-1)
1591 // erase current line
1592 while (ind--) BackSpace();
1599 write(STDOUT_FILENO,line,ind);
1603 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1605 PrintChar(line[ind]);
1610 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1618 write(STDOUT_FILENO,"\n\r",2);
1626 //=======================================================================
1627 void Interpreter::GetLineFromPrompt(std::string& s)
1653 //=======================================================================
1659 //=======================================================================
1660 void Interpreter::CommandLineInterpreter()
1662 bbtkDebugMessageInc("Interpreter",9,
1663 "Interpreter::CommandLineInterpreter()"<<std::endl);
1665 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1666 // Initialise the tty in non canonical mode with no echo
1667 // oter remembers the previous settings to restore them after
1668 struct termios ter,oter;
1671 ter.c_lflag &= ~ECHO;
1672 ter.c_lflag &= ~ICANON;
1675 tcsetattr(0,TCSANOW,&ter);
1678 mCommandLine = true;
1680 bool insideComment = false; // for multiline comment
1686 GetLineFromPrompt(line);
1687 InterpretLine(line, insideComment);
1689 catch (QuitException e)
1691 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1694 catch (bbtk::Exception e)
1698 catch (std::exception& e)
1700 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1704 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1709 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1710 tcsetattr(0,TCSANOW,&oter);
1713 std::cout << "Good bye !" << std::endl;
1715 bbtkDebugDecTab("Interpreter",9);
1718 //=======================================================================
1719 void Interpreter::Graph(const std::vector<std::string>& words)
1722 bool system_display = true;
1724 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1725 system_display = false;
1727 if (words.size()==1)
1729 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1731 else if (words.size()==2)
1733 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1735 else if (words.size()==3)
1737 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1739 else if (words.size()==4)
1741 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1743 else if (words.size()==5)
1745 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1747 else if (words.size()==6)
1749 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1751 else if (words.size()==7)
1753 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1756 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1757 mUser->InterpreterUserViewHtmlPage(page);
1760 //=======================================================================
1763 //=======================================================================
1764 void Interpreter::Index(const std::string& filename,
1765 const std::string& type)
1767 Factory::IndexEntryType t;
1768 if (type=="Initials") t = Factory::Initials;
1769 else if (type=="Categories") t = Factory::Categories;
1770 else if (type=="Packages") t = Factory::Packages;
1771 else if (type=="Adaptors") t = Factory::Adaptors;
1773 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1775 //=======================================================================