1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/20 11:04:57 $
7 Version: $Revision: 1.49 $
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()
51 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
52 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
53 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
55 mExecuter = new bbtk::Executer();
56 mExecuter->SetInterpreter(this);
58 // For the time being, comment out previous line, and
59 // uncomment next line to check Transcriptor
61 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
63 // Builds the commands dict
66 info.category = "new";
70 info.syntax = "new <type> <name>";
71 info.help = "Creates a new black box of type <type> with name <name>";
72 mCommandDict[info.category] = info;
74 info.category = "delete";
78 info.syntax = "delete <box>";
79 info.help = "Deletes the black box of name <box>";
80 mCommandDict[info.category] = info;
82 info.category = "connect";
86 info.syntax = "connect <box1.output> <box2.input>";
87 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
88 mCommandDict[info.category] = info;
90 info.category = "print";
94 info.syntax = "print <string>";
95 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').";
96 mCommandDict[info.category] = info;
98 info.category = "exec";
102 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
103 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.";
104 mCommandDict[info.category] = info;
106 info.category = "package";
109 info.code = cPackage;
110 info.syntax = "package <name>";
111 info.help = "Begins the definition of a package.";
112 mCommandDict[info.category] = info;
114 info.category = "endpackage";
117 info.code = cEndPackage;
118 info.syntax = "endpackage";
119 info.help = "Ends the definition of a package.";
120 mCommandDict[info.category] = info;
122 info.category = "define";
126 info.syntax = "define <type> [<package>]";
127 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.";
128 mCommandDict[info.category] = info;
130 info.category = "endefine";
133 info.code = cEndDefine;
134 info.syntax = "endefine";
135 info.help = "Ends the definition of a new type of complex black box";
136 mCommandDict[info.category] = info;
138 info.category = "input";
142 info.syntax = "input <name> <box.input> <help>";
143 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";
144 mCommandDict[info.category] = info;
146 info.category = "output";
150 info.syntax = "output <name> <box.output> <help>";
151 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";
152 mCommandDict[info.category] = info;
154 info.category = "set";
158 info.syntax = "set <box.input> <value>";
159 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";
160 mCommandDict[info.category] = info;
162 info.category = "config"; // JPR
166 info.syntax = "config";
167 info.help = "Prints the value of all configuration parameters";
168 mCommandDict[info.category] = info;
170 info.category = "index"; // LG
175 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
176 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.";
177 mCommandDict[info.category] = info;
179 info.category = "reset";
183 info.syntax = "reset";
184 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
185 mCommandDict[info.category] = info;
187 info.category = "author";
191 info.syntax = "author <string>";
192 info.help = "Adds the string <string> to the author information of the black box being defined";
193 mCommandDict[info.category] = info;
195 info.category = "category"; //JP
198 info.code = cCategory;
199 info.syntax = "category <list of items, separated by ;>";
200 info.help = "Adds the string <string> to the category information of the black box being defined";
201 mCommandDict[info.category] = info;
203 info.category = "description";
206 info.code = cDescription;
207 info.syntax = "description <string>";
208 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
209 mCommandDict[info.category] = info;
211 info.category = "help";
215 info.syntax = "help";
216 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>";
217 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.";
218 mCommandDict[info.category] = info;
220 info.category = "message";
223 info.code = cMessage;
224 info.syntax = "message <kind> <level>";
225 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;
227 info.category = "include";
230 info.code = cInclude;
231 info.syntax = "include <filename> [source]";
232 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).";
233 mCommandDict[info.category] = info;
235 info.category = "quit";
239 info.syntax = "quit";
240 info.help = "Quits the program (during script execution it stops the complete execution)";
241 mCommandDict[info.category] = info;
243 info.category = "load";
247 info.syntax = "load <packagename>";
248 info.help = "Loads the black box package <packagename>";
249 mCommandDict[info.category] = info;
251 info.category = "unload";
255 info.syntax = "unload <packagename>";
256 info.help = "Unloads the black box package <packagename>";
257 mCommandDict[info.category] = info;
259 info.category = "graph";
263 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 ]]]]]]";
264 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')";
265 mCommandDict[info.category] = info;
268 info.category = "workspace";
271 info.code = cWorkspace;
272 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
273 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.";
274 mCommandDict[info.category] = info;
277 bbtkDebugDecTab("Interpreter",9);
280 //=======================================================================
284 //=======================================================================
288 Interpreter::~Interpreter()
290 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
293 bbtkDebugDecTab("Interpreter",9);
295 //=======================================================================
298 //=======================================================================
302 Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
304 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
306 bool exm = mCommandLine;
307 mCommandLine = false;
309 ExitStatus status = OK;
313 SwitchToFile(filename);
315 bool insideComment = false; // for multiline comment
316 while (mFile.size()>0)
318 while (!mFile.back()->eof()) {
321 mFile.back()->getline(buf,500);
322 std::string str(buf);
323 int size=str.length();
324 if ( str[ size-1 ]==13 )
329 InterpretLine(str, insideComment);
335 catch (QuitException e)
339 catch (bbtk::Exception e)
341 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
342 if (mFileName.size()) {
343 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
344 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
348 catch (std::exception& e)
350 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
351 if (mFileName.size()) {
352 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
353 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
359 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
360 if (mFileName.size()) {
361 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
362 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
368 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
369 bbtkDecTab("Interpreter",9);
375 //=======================================================================
378 //=======================================================================
382 Interpreter::ExitStatus
383 Interpreter::InterpretBuffer( std::stringstream* buffer )
385 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
387 bool exm = mCommandLine;
388 mCommandLine = false;
390 ExitStatus status = OK;
394 SwitchToStream(buffer);
395 bool insideComment = false; // for multiline comment
396 while (mFile.size()>0)
398 while (!mFile.back()->eof()) {
401 mFile.back()->getline(buf,500);
402 std::string str(buf);
404 int size=str.length();
405 if ( str[ size-1 ]==13 )
410 InterpretLine(str, insideComment);
417 catch (QuitException e)
421 catch (bbtk::Exception e)
423 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
424 if (mFileName.size())
426 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
427 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
431 catch (std::exception& e)
433 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
434 if (mFileName.size())
436 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
437 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
444 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
445 if (mFileName.size())
447 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
448 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
454 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
455 bbtkDecTab("Interpreter",9);
460 //=======================================================================
462 //=======================================================================
463 /// Runs the interpretation of a command
464 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
466 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
468 ExitStatus status = OK;
472 bool insideComment = false;
473 InterpretLine(line, insideComment);
475 catch (QuitException e)
479 catch (bbtk::Exception e)
481 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
484 catch (std::exception& e)
486 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
492 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
497 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
499 bbtkDecTab("Interpreter",9);
505 //=======================================================================
509 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
511 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
512 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
514 std::vector<std::string> words;
515 SplitLine(line,words);
520 bbtkDebugDecTab("Interpreter",9);
524 // Single line comment : # or //
525 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
527 bbtkDebugDecTab("Interpreter",9);
528 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
532 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
534 if (words[0][0]=='/' && words[0][1]=='*')
536 bbtkDebugDecTab("Interpreter",9);
537 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
538 insideComment = true;
542 if (words[0][0]=='*' && words[0][1]=='/')
544 bbtkDebugDecTab("Interpreter",9);
545 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
546 if ( !insideComment ) {
547 bbtkDebugDecTab("Interpreter",9);
548 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
550 insideComment = false;
556 bbtkDebugDecTab("Interpreter",9);
557 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
562 CommandInfoType command;
563 InterpretCommand(words,command);
565 bbtkDebugMessage("Interpreter",9,
566 "Command='"<<command.category
567 <<"' code="<<command.code<<std::endl);
569 std::string left,right,left2,right2;
570 std::string filename;
571 switch (command.code)
574 mExecuter->Create(words[1],words[2]);
579 // mExecuter->Remove(words[1]);
583 Utilities::SplitAroundFirstDot(words[1],left,right);
584 Utilities::SplitAroundFirstDot(words[2],left2,right2);
585 mExecuter->Connect(left,right,left2,right2);
589 mExecuter->BeginPackage(words[1]);
593 mExecuter->EndPackage();
597 if (mFileName.size()>0)
599 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
603 mExecuter->Define(words[1],"",filename);
607 mExecuter->Define(words[1],words[2],filename);
612 mExecuter->EndDefine();
616 Print(words[1]); /// \todo use generate command
620 if (words[1]=="freeze")
621 mExecuter->SetNoExecMode(true);
622 else if (words[1]=="unfreeze")
623 mExecuter->SetNoExecMode(false);
625 mExecuter->Update(words[1]);
629 Utilities::SplitAroundFirstDot(words[2],left,right);
630 mExecuter->DefineInput(words[1],left,right,words[3]);
634 Utilities::SplitAroundFirstDot(words[2],left,right);
635 mExecuter->DefineOutput(words[1],left,right,words[3]);
639 Utilities::SplitAroundFirstDot(words[1],left,right);
640 mExecuter->Set(left,right,words[2]);
644 mExecuter->Author(words[1]);
648 mExecuter->Category(words[1]);
653 Index("tmp_index.html");
654 else if (words.size()==2)
656 else if (words.size()==3)
657 Index(words[1],words[2]);
661 mExecuter->Description(words[1]);
671 bbtk::MessageManager::PrintInfo();
675 sscanf(words[2].c_str(),"%d",&level);
676 bbtk::MessageManager::SetMessageLevel(words[1],level);
689 this->mExecuter->Reset();
695 InterpretFile(words[1]);
699 SwitchToFile(words[1]);
701 // if 'source' was given
704 GetExecuter()->SetCurrentFileName(words[1]);
709 GetExecuter()->GetFactory()->LoadPackage(words[1]);
713 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
718 throw QuitException();
722 if (words.size() == 2)
724 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
725 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
729 mExecuter->SetWorkspaceName(words[2]);
734 bbtkInternalError("should not reach here !!!");
737 bbtkDecTab("Interpreter",9);
739 //=======================================================================
745 //=======================================================================
749 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
751 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
753 std::string delimiters = "\"";
754 std::vector<std::string> quote;
755 Utilities::SplitString(str,delimiters,quote);
758 std::vector<std::string>::iterator i;
759 for (i=quote.begin(); i!=quote.end(); )
761 Utilities::SplitString(*i,delimiters,tokens);
765 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
766 tokens.push_back(*i);
771 for (i=tokens.begin(); i!=tokens.end(); ++i)
773 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
775 bbtkDebugMessageCont("Interpreter",9,std::endl);
777 bbtkDebugDecTab("Interpreter",9);
779 //=======================================================================
782 //=======================================================================
783 // Replaces substrings "\\n" by a real carriage return "\n"
784 void SubsBackslashN ( std::string& s )
786 std::string ss("\\n");
787 std::string::size_type pos = 0;
790 while ( pos != std::string::npos )
792 s.replace(pos,2,cr,1);
793 pos = s.find(ss, pos-1);
796 //=======================================================================
799 //=======================================================================
803 void Interpreter::Print( const std::string& str)
805 if (mExecuter->GetNoExecMode()) return;
807 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
810 // InterpretLine ("load std")
811 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
812 // InterpretLine("new Print _P_")
813 // InterpretLine("connect _C_.Out _P_.In")
817 std::vector<std::string> chains;
818 std::string delimiters("$");
820 // Skip delimiters at beginning.
821 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
823 if (lastPos>0) is_text = false;
825 // Find first delimiter.
826 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
828 while (std::string::npos != pos || std::string::npos != lastPos)
832 // Found a text token, add it to the vector.
833 chains.push_back(str.substr(lastPos, pos - lastPos));
834 // std::string token = str.substr(lastPos, pos - lastPos)
835 // InterpretLine("set _C_.In%num% %token%")
841 // is an output (between $$) : decode
842 std::string tok,box,output;
843 tok = str.substr(lastPos, pos - lastPos);
844 Utilities::SplitAroundFirstDot(tok,box,output);
845 chains.push_back( mExecuter->Get(box,output) );
847 // InterpretLine("connect %tok% _C_.In%num%")
850 // Skip delimiters. Note the "not_of"
851 lastPos = str.find_first_not_of(delimiters, pos);
852 // Find next delimiter
853 pos = str.find_first_of(delimiters, lastPos);
858 // InterpretLine("exec _P_")
859 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
861 std::vector<std::string>::iterator i;
862 for (i= chains.begin(); i!=chains.end(); ++i)
864 // bbtkMessage("Echo",1,*i);
868 std::cout << std::endl;
869 bbtkDebugDecTab("Interpreter",9);
872 //=======================================================================
877 // ===================================================================================
879 void Interpreter::SwitchToFile( const std::string& name )
881 // Note : in the following :
882 // name : the user supplied name
883 // - abreviated name e.g. scr scr.bbs
884 // - relative full name e.g. ./scr.bbs ../../scr.bbs
885 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
886 // same for Windows, with c:, d: ...
888 // use ./directory/subdir/scrname.bbs
891 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
892 <<name<<"\")"<<std::endl);
894 std::vector<std::string> script_paths;
895 std::string fullPathScriptName; // full path script name
896 std::string pkgname; // e.g. <scriptname>.bbs
897 std::vector<std::string> Filenames;
899 // The following is *NOT* a debug time message :
900 // It's a user intended message.
901 // Please don't remove it.
902 bbtkMessage("Interpreter",1,
903 "look for : [" << name
904 << "]" << std::endl);
905 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
908 pkgname = Utilities::ExtractScriptName(name,upath);
910 bbtkMessage("Interpreter",1,
911 "extract : pkgname [" << pkgname
912 << "] upath [" << upath << "]" << std::endl);
913 bool fullnameGiven = false;
914 bool foundFile = false;
916 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
920 std::stringstream* stream = new std::stringstream;
921 //if (upath.size()!=0) // avoid troubles for "*"
923 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
925 int nbFiles = Utilities::Explore(upath, false, Filenames);
927 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
929 int lgr = (*i).size();
931 continue; // ignore non .bbs file
932 if ((*i).substr(lgr-4, 4) != ".bbs")
935 (*stream) << "include " << *i << "\n";
940 bbtkMessage("Interpreter",2,
941 "WARNING : No '.bbs' file found in ["
942 << upath << "]" << std::endl);
944 SwitchToStream(stream);
950 std::vector<std::string>::iterator i;
951 std::string fullDirectoryName;
952 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
956 // we *really* want '.' to be the current working directory
958 char buf[2048]; // for getcwd
959 char * currentDir = getcwd(buf, 2048);
960 std::string cwd(currentDir);
964 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
966 // without last slash "\"
967 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
969 // Check if library exists
970 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
972 // The following is *NOT* a debug time message :
973 // It's a user intended message.
974 // Please don't remove it.
975 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
976 <<"] : doesn't exist" <<std::endl);
977 continue; // try next path
982 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
985 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
987 int lgr = (*i).size();
989 continue; // ignore non .bbs file
990 if ((*i).substr(lgr-4, 4) != ".bbs")
993 (*stream) << "include " << *i << "\n";
997 bbtkMessage("Interpreter",1,
998 "WARNING : No '.bbs' file found in ["
999 << fullDirectoryName << "]" << std::endl);
1001 SwitchToStream(stream);
1004 //break; // a directory was found; we stop iterating
1005 // LG : No! We want all files included !
1010 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1011 // (not only a plain script name)
1012 // we trust him, and try to expland the directory name
1013 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1015 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1018 // ===========================================================check user supplied location
1019 fullnameGiven = true;
1021 fullPathScriptName = Utilities::ExpandLibName(name, false);
1023 // allow user to always forget ".bbs"
1024 int l = fullPathScriptName.size();
1030 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1032 fullPathScriptName = fullPathScriptName + ".bbs";
1037 fullPathScriptName = fullPathScriptName + ".bbs";
1040 if ( Utilities::FileExists(fullPathScriptName))
1047 // =============================================================== iterate on the paths
1050 std::vector<std::string>::iterator i;
1051 for (i=script_paths.begin();i!=script_paths.end();++i)
1054 // we *really* want '.' to be the current working directory
1056 char buf[2048]; // for getcwd
1057 char * currentDir = getcwd(buf, 2048);
1058 std::string cwd(currentDir);
1062 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1064 // Check if library exists
1065 if ( ! Utilities::FileExists(fullPathScriptName) )
1067 // The following is *NOT* a debug time message :
1068 // It's a user intended message.
1069 // Please don't remove it.
1070 bbtkMessage("Interpreter",2,
1071 " [" <<fullPathScriptName <<"] : doesn't exist"
1073 continue; // try next path
1075 bbtkMessage("Interpreter",2,
1076 " [" <<fullPathScriptName
1077 <<"] : found" <<std::endl);
1079 break; // a script was found; we stop iterating
1081 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1087 if(fullPathScriptName == "")
1088 bbtkError("Path ["<<upath<<"] doesn't exist");
1090 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1092 bbtkError("No ["<<pkgname<<".bbs] script found");
1096 LoadScript(fullPathScriptName,name);
1102 void Interpreter::SwitchToStream( std::stringstream* stream )
1104 mFile.push_back(stream);
1105 std::ostringstream buffer_name;
1107 buffer_name << "buffer_" ;
1109 if (mFileName.size()>0 )
1111 buffer_name << mFileName.back() << "_" << mLine.back();
1113 mFileName.push_back(buffer_name.str());
1114 mIncludeFileName.push_back(buffer_name.str());
1118 //=======================================================================
1120 void Interpreter::LoadScript( std::string fullPathScriptName,
1121 std::string includeScriptName)
1123 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1125 bool okScriptExist=false;
1126 int iStrScript,sizeVecStricpt=mFileName.size();
1127 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1129 if (mFileName[iStrScript] == fullPathScriptName )
1135 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1136 // if (okScriptExist==true)
1138 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1139 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1144 s = new std::ifstream;
1145 s->open(fullPathScriptName.c_str());
1148 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1152 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1153 << "] found" << std::endl);
1156 mFileName.push_back(fullPathScriptName);
1157 mIncludeFileName.push_back(includeScriptName);
1162 //=======================================================================
1166 void Interpreter::CloseCurrentFile()
1168 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1171 if (mFile.size()==0)
1173 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1177 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1179 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1180 if (file!=0) file->close();
1182 delete mFile.back();
1184 mFileName.pop_back();
1185 mIncludeFileName.pop_back();
1188 bbtkDebugMessage("Interpreter",9," Remains "
1190 <<" open"<<std::endl);
1191 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1194 //=======================================================================
1196 //=======================================================================
1200 void Interpreter::CloseAllFiles()
1202 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1205 while (mFile.size() != 0)
1209 mFile.back()->close();
1210 delete mFile.back();
1212 bbtkDebugMessage("Interpreter",9,
1213 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1214 mFileName.pop_back();
1215 mIncludeFileName.pop_back();
1219 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1222 //=======================================================================
1226 //=======================================================================
1230 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1231 CommandInfoType& info )
1233 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1235 // searches the command category
1236 CommandDictType::iterator c;
1237 c = mCommandDict.find(words[0]);
1238 if ( c == mCommandDict.end() ) {
1239 bbtkError(words[0]<<" : unknown command");
1242 // tests the number of args
1243 if ( ( words.size()-1 < c->second.argmin ) ||
1244 ( words.size()-1 > c->second.argmax ) )
1246 HelpCommand(words[0]);
1247 bbtkError(words[0]<<" : wrong number of arguments");
1251 bbtkDecTab("Interpreter",9);
1253 //=======================================================================
1256 //=======================================================================
1257 /// Displays help on all the commands
1258 void Interpreter::Help(const std::vector<std::string>& words)
1260 unsigned int nbarg = words.size()-1;
1268 if (words[1]=="packages")
1270 GetExecuter()->GetFactory()->PrintPackages(true);
1275 HelpCommand(words[1]);
1277 catch (bbtk::Exception e)
1281 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1285 ConfigurationFile::GetInstance().Get_doc_path();
1286 url += "/bbdoc/" + words[1] + "/index.html";
1287 if (Utilities::FileExists(url))
1289 mUser->InterpreterUserViewHtmlPage(url);
1293 catch (bbtk::Exception f)
1297 std::string package;
1298 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1302 ConfigurationFile::GetInstance().Get_doc_path();
1303 url += "/bbdoc/" + package + "/index.html";
1304 if (Utilities::FileExists(url))
1306 url += "#" + words[1];
1307 mUser->InterpreterUserViewHtmlPage(url);
1311 catch (bbtk::Exception g)
1315 GetExecuter()->ShowRelations(words[1],"0","9999");
1317 catch (bbtk::Exception h){
1318 bbtkError("\""<<words[1].c_str()
1319 <<"\" is not a known command, package, black box type or black box name");
1327 if (words[2]=="all")
1329 if ( words[1]=="packages" )
1331 GetExecuter()->GetFactory()->PrintPackages(true,true);
1336 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1338 catch (bbtk::Exception f)
1344 HelpCommand(words[0]);
1345 bbtkError(words[0]<<" : syntax error");
1350 bbtkError("Should not reach here !!!");
1353 //=======================================================================
1355 //===================================================================
1356 /// Displays the Configuration
1357 void Interpreter::Config() const
1359 ConfigurationFile::GetInstance().GetHelp(1);
1361 //===================================================================
1363 //=======================================================================
1364 /// Displays help on all the commands
1365 void Interpreter::HelpCommands()
1367 std::cout << "Available commands :" << std::endl;
1368 CommandDictType::iterator i;
1369 for ( i = mCommandDict.begin();
1370 i != mCommandDict.end();
1372 std::cout << " " << i->first << std::endl;
1373 // std::cout << " usage : " << i->second.syntax << std::endl;
1374 // std::cout << " " << i->second.help << std::endl;
1378 //=======================================================================
1381 //=======================================================================
1382 /// Displays help on a particular commands
1383 void Interpreter::HelpCommand(const std::string& s)
1385 CommandDictType::iterator c;
1386 c = mCommandDict.find(s);
1387 if ( c == mCommandDict.end() ) {
1388 bbtkError(s<<" : Unknown command");
1390 // std::cout << " " << s << " : "<< std::endl;
1391 // CommandParamDictType::iterator i;
1392 // for ( i = c->second.begin();
1393 // i != c->second.end();
1395 std::cout << " usage : " << c->second.syntax << std::endl;
1396 std::cout << " " << c->second.help << std::endl;
1399 //=======================================================================
1402 //=======================================================================
1403 /// Fills the vector commands with the commands which
1404 /// have the first n chars of buf for prefix
1405 /// TODO : skip initial spaces in buf and also return the position of first
1406 /// non blank char in buf
1407 void Interpreter::FindCommandsWithPrefix( char* buf,
1409 std::vector<std::string>& commands )
1411 CommandDictType::const_iterator i;
1412 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1414 if ((i->first).find(buf,0,n) == 0)
1415 commands.push_back(i->first);
1418 //=======================================================================
1422 //=======================================================================
1423 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1425 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1426 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1428 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1429 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1430 // E.G. STORE THIS IN bbtk_config.xml
1431 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1432 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1433 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1434 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1435 #define BBTK_BACKSPACE_KBCODE 0x00000008
1436 #define BBTK_DEL_KBCODE 0x0000007F
1437 #define BBTK_SPACE_KBCODE 0x00000020
1439 //=======================================================================
1440 void Interpreter::GetLineFromPrompt(std::string& s)
1445 int MAX_LINE_SIZE = 160;
1446 int MAX_HISTORY_SIZE = 100;
1448 char* newline = new char[MAX_LINE_SIZE];
1449 memset(newline,0,MAX_LINE_SIZE);
1450 char* histline = new char[MAX_LINE_SIZE];
1451 memset(histline,0,MAX_LINE_SIZE);
1453 char* line = newline;
1454 int hist = mHistory.size();
1460 read ( STDIN_FILENO, &c, 4) ;
1462 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1464 // Printable character
1465 if ( (ind<MAX_LINE_SIZE-1) &&
1466 ( c >= BBTK_SPACE_KBCODE ) &&
1467 ( c < BBTK_DEL_KBCODE ))
1475 // delete the unused line
1481 // empty lines are not stored in from history
1484 // if history too long : delete oldest command
1485 if (mHistory.size()>MAX_HISTORY_SIZE)
1487 delete mHistory.front();
1488 mHistory.pop_front();
1490 mHistory.push_back(line);
1495 else if ( (ind>0) &&
1496 ((c == BBTK_BACKSPACE_KBCODE) ||
1497 (c == BBTK_DEL_KBCODE)) )
1505 // TODO : Command completion
1506 std::vector<std::string> commands;
1507 FindCommandsWithPrefix( line,ind,commands);
1508 if (commands.size()==1)
1510 std::string com = *commands.begin();
1511 for (; ind<com.size(); ++ind)
1513 PrintChar(com[ind]);
1519 else if (commands.size()>1)
1521 std::vector<std::string>::iterator i;
1523 for (i=commands.begin();i!=commands.end();++i)
1525 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1528 write(STDOUT_FILENO,"\n> ",3);
1529 //for (int j=0;j<ind;++j)
1531 write(STDOUT_FILENO,line,ind);
1535 // Arrow up : back in history
1536 else if (c==BBTK_UP_ARROW_KBCODE)
1540 // erase current line
1541 while (ind--) BackSpace();
1545 strcpy(histline,mHistory[hist]);
1549 write(STDOUT_FILENO,line,ind);
1552 // Arrow down : down in history
1553 else if (c==BBTK_DOWN_ARROW_KBCODE)
1555 if (hist<mHistory.size()-1)
1557 // erase current line
1558 while (ind--) BackSpace();
1562 strcpy(histline,mHistory[hist]);
1566 write(STDOUT_FILENO,line,ind);
1568 // end of history : switch back to newline
1569 else if (hist==mHistory.size()-1)
1571 // erase current line
1572 while (ind--) BackSpace();
1579 write(STDOUT_FILENO,line,ind);
1583 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1585 PrintChar(line[ind]);
1590 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1598 write(STDOUT_FILENO,"\n\r",2);
1606 //=======================================================================
1607 void Interpreter::GetLineFromPrompt(std::string& s)
1633 //=======================================================================
1639 //=======================================================================
1640 void Interpreter::CommandLineInterpreter()
1642 bbtkDebugMessageInc("Interpreter",9,
1643 "Interpreter::CommandLineInterpreter()"<<std::endl);
1645 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1646 // Initialise the tty in non canonical mode with no echo
1647 // oter remembers the previous settings to restore them after
1648 struct termios ter,oter;
1651 ter.c_lflag &= ~ECHO;
1652 ter.c_lflag &= ~ICANON;
1655 tcsetattr(0,TCSANOW,&ter);
1658 mCommandLine = true;
1660 bool insideComment = false; // for multiline comment
1666 GetLineFromPrompt(line);
1667 InterpretLine(line, insideComment);
1669 catch (QuitException e)
1671 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1674 catch (bbtk::Exception e)
1678 catch (std::exception& e)
1680 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1684 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1689 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1690 tcsetattr(0,TCSANOW,&oter);
1693 std::cout << "Good bye !" << std::endl;
1695 bbtkDebugDecTab("Interpreter",9);
1698 //=======================================================================
1699 void Interpreter::Graph(const std::vector<std::string>& words)
1702 bool system_display = true;
1704 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1705 system_display = false;
1707 if (words.size()==1)
1709 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1711 else if (words.size()==2)
1713 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1715 else if (words.size()==3)
1717 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1719 else if (words.size()==4)
1721 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1723 else if (words.size()==5)
1725 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1727 else if (words.size()==6)
1729 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1731 else if (words.size()==7)
1733 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1736 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1737 mUser->InterpreterUserViewHtmlPage(page);
1740 //=======================================================================
1743 //=======================================================================
1744 void Interpreter::Index(const std::string& filename,
1745 const std::string& type)
1747 Factory::IndexEntryType t;
1748 if (type=="Initials") t = Factory::Initials;
1749 else if (type=="Categories") t = Factory::Categories;
1750 else if (type=="Packages") t = Factory::Packages;
1751 else if (type=="Adaptors") t = Factory::Adaptors;
1753 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1755 //=======================================================================