1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/20 09:51:28 $
7 Version: $Revision: 1.48 $
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);
314 bool insideComment = false; // for multiline comment
315 while (mFile.size()>0)
317 while (!mFile.back()->eof()) {
320 mFile.back()->getline(buf,500);
321 std::string str(buf);
322 int size=str.length();
323 if ( str[ size-1 ]==13 )
328 InterpretLine(str, insideComment);
334 catch (QuitException e)
338 catch (bbtk::Exception e)
340 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
341 if (mFileName.size()) {
342 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
343 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
347 catch (std::exception& e)
349 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
350 if (mFileName.size()) {
351 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
352 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
358 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
359 if (mFileName.size()) {
360 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
361 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
367 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
368 bbtkDecTab("Interpreter",9);
374 //=======================================================================
377 //=======================================================================
381 Interpreter::ExitStatus
382 Interpreter::InterpretBuffer( std::stringstream* buffer )
384 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
386 bool exm = mCommandLine;
387 mCommandLine = false;
389 ExitStatus status = OK;
393 SwitchToStream(buffer);
394 bool insideComment = false; // for multiline comment
395 while (mFile.size()>0)
397 while (!mFile.back()->eof()) {
400 mFile.back()->getline(buf,500);
401 std::string str(buf);
403 int size=str.length();
404 if ( str[ size-1 ]==13 )
409 InterpretLine(str, insideComment);
416 catch (QuitException e)
420 catch (bbtk::Exception e)
422 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
423 if (mFileName.size())
425 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
426 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
430 catch (std::exception& e)
432 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
433 if (mFileName.size())
435 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
436 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
443 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
444 if (mFileName.size())
446 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
447 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
453 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
454 bbtkDecTab("Interpreter",9);
459 //=======================================================================
461 //=======================================================================
462 /// Runs the interpretation of a command
463 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
465 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
467 ExitStatus status = OK;
471 bool insideComment = false;
472 InterpretLine(line, insideComment);
474 catch (QuitException e)
478 catch (bbtk::Exception e)
480 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
483 catch (std::exception& e)
485 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
491 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
496 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
498 bbtkDecTab("Interpreter",9);
504 //=======================================================================
508 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
510 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
511 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
513 std::vector<std::string> words;
514 SplitLine(line,words);
519 bbtkDebugDecTab("Interpreter",9);
523 // Single line comment : # or //
524 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
526 bbtkDebugDecTab("Interpreter",9);
527 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
531 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
533 if (words[0][0]=='/' && words[0][1]=='*')
535 bbtkDebugDecTab("Interpreter",9);
536 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
537 insideComment = true;
541 if (words[0][0]=='*' && words[0][1]=='/')
543 bbtkDebugDecTab("Interpreter",9);
544 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
545 if ( !insideComment ) {
546 bbtkDebugDecTab("Interpreter",9);
547 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
549 insideComment = false;
555 bbtkDebugDecTab("Interpreter",9);
556 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
561 CommandInfoType command;
562 InterpretCommand(words,command);
564 bbtkDebugMessage("Interpreter",9,
565 "Command='"<<command.category
566 <<"' code="<<command.code<<std::endl);
568 std::string left,right,left2,right2;
569 std::string filename;
570 switch (command.code)
573 mExecuter->Create(words[1],words[2]);
578 // mExecuter->Remove(words[1]);
582 Utilities::SplitAroundFirstDot(words[1],left,right);
583 Utilities::SplitAroundFirstDot(words[2],left2,right2);
584 mExecuter->Connect(left,right,left2,right2);
588 mExecuter->BeginPackage(words[1]);
592 mExecuter->EndPackage();
596 if (mFileName.size()>0)
598 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
602 mExecuter->Define(words[1],"",filename);
606 mExecuter->Define(words[1],words[2],filename);
611 mExecuter->EndDefine();
615 Print(words[1]); /// \todo use generate command
619 if (words[1]=="freeze")
620 mExecuter->SetNoExecMode(true);
621 else if (words[1]=="unfreeze")
622 mExecuter->SetNoExecMode(false);
624 mExecuter->Update(words[1]);
628 Utilities::SplitAroundFirstDot(words[2],left,right);
629 mExecuter->DefineInput(words[1],left,right,words[3]);
633 Utilities::SplitAroundFirstDot(words[2],left,right);
634 mExecuter->DefineOutput(words[1],left,right,words[3]);
638 Utilities::SplitAroundFirstDot(words[1],left,right);
639 mExecuter->Set(left,right,words[2]);
643 mExecuter->Author(words[1]);
647 mExecuter->Category(words[1]);
652 Index("tmp_index.html");
653 else if (words.size()==2)
655 else if (words.size()==3)
656 Index(words[1],words[2]);
660 mExecuter->Description(words[1]);
670 bbtk::MessageManager::PrintInfo();
674 sscanf(words[2].c_str(),"%d",&level);
675 bbtk::MessageManager::SetMessageLevel(words[1],level);
688 this->mExecuter->Reset();
694 InterpretFile(words[1]);
698 SwitchToFile(words[1]);
700 // if 'source' was given
703 GetExecuter()->SetCurrentFileName(words[1]);
708 GetExecuter()->GetFactory()->LoadPackage(words[1]);
712 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
717 throw QuitException();
721 if (words.size() == 2)
723 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
724 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
728 mExecuter->SetWorkspaceName(words[2]);
733 bbtkInternalError("should not reach here !!!");
736 bbtkDecTab("Interpreter",9);
738 //=======================================================================
744 //=======================================================================
748 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
750 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
752 std::string delimiters = "\"";
753 std::vector<std::string> quote;
754 Utilities::SplitString(str,delimiters,quote);
757 std::vector<std::string>::iterator i;
758 for (i=quote.begin(); i!=quote.end(); )
760 Utilities::SplitString(*i,delimiters,tokens);
764 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
765 tokens.push_back(*i);
770 for (i=tokens.begin(); i!=tokens.end(); ++i)
772 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
774 bbtkDebugMessageCont("Interpreter",9,std::endl);
776 bbtkDebugDecTab("Interpreter",9);
778 //=======================================================================
781 //=======================================================================
782 // Replaces substrings "\\n" by a real carriage return "\n"
783 void SubsBackslashN ( std::string& s )
785 std::string ss("\\n");
786 std::string::size_type pos = 0;
789 while ( pos != std::string::npos )
791 s.replace(pos,2,cr,1);
792 pos = s.find(ss, pos-1);
795 //=======================================================================
798 //=======================================================================
802 void Interpreter::Print( const std::string& str)
804 if (mExecuter->GetNoExecMode()) return;
806 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
809 // InterpretLine ("load std")
810 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
811 // InterpretLine("new Print _P_")
812 // InterpretLine("connect _C_.Out _P_.In")
816 std::vector<std::string> chains;
817 std::string delimiters("$");
819 // Skip delimiters at beginning.
820 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
822 if (lastPos>0) is_text = false;
824 // Find first delimiter.
825 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
827 while (std::string::npos != pos || std::string::npos != lastPos)
831 // Found a text token, add it to the vector.
832 chains.push_back(str.substr(lastPos, pos - lastPos));
833 // std::string token = str.substr(lastPos, pos - lastPos)
834 // InterpretLine("set _C_.In%num% %token%")
840 // is an output (between $$) : decode
841 std::string tok,box,output;
842 tok = str.substr(lastPos, pos - lastPos);
843 Utilities::SplitAroundFirstDot(tok,box,output);
844 chains.push_back( mExecuter->Get(box,output) );
846 // InterpretLine("connect %tok% _C_.In%num%")
849 // Skip delimiters. Note the "not_of"
850 lastPos = str.find_first_not_of(delimiters, pos);
851 // Find next delimiter
852 pos = str.find_first_of(delimiters, lastPos);
857 // InterpretLine("exec _P_")
858 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
860 std::vector<std::string>::iterator i;
861 for (i= chains.begin(); i!=chains.end(); ++i)
863 // bbtkMessage("Echo",1,*i);
867 std::cout << std::endl;
868 bbtkDebugDecTab("Interpreter",9);
871 //=======================================================================
876 // ===================================================================================
878 void Interpreter::SwitchToFile( const std::string& name )
880 // Note : in the following :
881 // name : the user supplied name
882 // - abreviated name e.g. scr scr.bbs
883 // - relative full name e.g. ./scr.bbs ../../scr.bbs
884 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
885 // same for Windows, with c:, d: ...
887 // use ./directory/subdir/scrname.bbs
890 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
891 <<name<<"\")"<<std::endl);
893 std::vector<std::string> script_paths;
894 std::string fullPathScriptName; // full path script name
895 std::string pkgname; // e.g. <scriptname>.bbs
896 std::vector<std::string> Filenames;
898 // The following is *NOT* a debug time message :
899 // It's a user intended message.
900 // Please don't remove it.
901 bbtkMessage("Interpreter",1,
902 "look for : [" << name
903 << "]" << std::endl);
904 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
907 pkgname = Utilities::ExtractScriptName(name,upath);
909 bbtkMessage("Interpreter",1,
910 "extract : pkgname [" << pkgname
911 << "] upath [" << upath << "]" << std::endl);
912 bool fullnameGiven = false;
913 bool foundFile = false;
915 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
917 // std::cout << "JPR================== * found, load all boxes " << std::endl;
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 // std::cout << "JPR================== absolute name, load all .bbs files " << std::endl;
926 int nbFiles = Utilities::Explore(upath, false, Filenames);
928 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
930 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
931 int lgr = (*i).size();
933 continue; // ignore non .bbs file
934 if ((*i).substr(lgr-4, 4) != ".bbs")
937 if (lgr > 10) // 10 -> '-appli.bbs'
939 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
940 continue; // ignore '-appli.bbs' files
944 (*stream) << "include " << *i << "\n";
945 //EED InterpretFile(*i);
950 bbtkMessage("Interpreter",2,
951 "WARNING : No '.bbs' file found in ["
952 << upath << "]" << std::endl);
954 SwitchToStream(stream);
960 std::vector<std::string>::iterator i;
961 std::string fullDirectoryName;
962 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
966 // we *really* want '.' to be the current working directory
968 char buf[2048]; // for getcwd
969 char * currentDir = getcwd(buf, 2048);
970 std::string cwd(currentDir);
974 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
976 // without last slash "\"
977 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
979 // Check if library exists
980 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
982 // The following is *NOT* a debug time message :
983 // It's a user intended message.
984 // Please don't remove it.
985 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
986 <<"] : doesn't exist" <<std::endl);
987 continue; // try next path
992 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
995 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
997 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
998 int lgr = (*i).size();
1000 continue; // ignore non .bbs file
1001 if ((*i).substr(lgr-4, 4) != ".bbs")
1004 if (lgr > 10) // 10 -> '-appli.bbs'
1006 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
1007 continue; // ignore '-appli.bbs' files
1011 (*stream) << "include " << *i << "\n";
1012 //EED InterpretFile(*i);
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 //std::string::size_type slash_position = name.find_last_of("/\\");
1032 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1033 // (not only a plain script name)
1034 // we trust him, and try to expland the directory name
1035 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1037 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1040 // ===========================================================check user supplied location
1041 fullnameGiven = true;
1043 fullPathScriptName = Utilities::ExpandLibName(name, false);
1045 // allow user to always forget ".bbs"
1046 int l = fullPathScriptName.size();
1052 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1054 fullPathScriptName = fullPathScriptName + ".bbs";
1059 fullPathScriptName = fullPathScriptName + ".bbs";
1062 if ( Utilities::FileExists(fullPathScriptName))
1069 // =============================================================== iterate on the paths
1072 std::vector<std::string>::iterator i;
1073 for (i=script_paths.begin();i!=script_paths.end();++i)
1076 // we *really* want '.' to be the current working directory
1078 char buf[2048]; // for getcwd
1079 char * currentDir = getcwd(buf, 2048);
1080 std::string cwd(currentDir);
1084 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1086 // Check if library exists
1087 if ( ! Utilities::FileExists(fullPathScriptName) )
1089 // The following is *NOT* a debug time message :
1090 // It's a user intended message.
1091 // Please don't remove it.
1092 bbtkMessage("Interpreter",2,
1093 " [" <<fullPathScriptName <<"] : doesn't exist"
1095 continue; // try next path
1097 bbtkMessage("Interpreter",2,
1098 " [" <<fullPathScriptName
1099 <<"] : found" <<std::endl);
1101 break; // a script was found; we stop iterating
1103 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1109 if(fullPathScriptName == "")
1110 bbtkError("Path ["<<upath<<"] doesn't exist");
1112 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1114 bbtkError("No ["<<pkgname<<".bbs] script found");
1118 LoadScript(fullPathScriptName,name);
1124 void Interpreter::SwitchToStream( std::stringstream* stream )
1126 //std::cout << "== 1 Entry in Interpreter::SwitchToStream " << std::endl;
1128 mFile.push_back(stream);
1129 //std::cout << " mFile.size() " << mFile.size() << std::endl;
1130 std::ostringstream buffer_name;
1132 buffer_name << "buffer_" ; // << bufferNb;
1134 // std::cout << " mFile.size() " << mFile.size() << std::endl;
1135 // std::cout << " mFileName.size() " << mFileName.size() << std::endl;
1136 // std::cout << " mLine.size() " << mLine.size() << std::endl;
1137 // std::vector<std::string>::iterator j = mFileName.begin();
1138 // std::cout << " mFileName.begin() succeeded" << std::endl;
1139 // std::cout << " mFileName[0] " << mFileName[0] << std::endl;
1140 //std::cout << " mFileName.begin() " << mFileName.begin() << std::endl;
1142 for( std::vector<std::string>::iterator i = mFileName.begin(); i!= mFileName.end(); ++i)
1145 std::cout << "Interpreter::SwitchToStream : mFileName [" << *i << "]" << std::endl;
1148 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1149 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1151 if (mFileName.size()>0 )// && (mFile.size()>0) ) // NO!!!
1153 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1154 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1155 buffer_name << mFileName.back() << "_" << mLine.back();
1157 //std::cout << "3 in Interpreter::SwitchToStream buffer_name :[" << buffer_name.str() << "]" << std::endl;
1158 mFileName.push_back(buffer_name.str());
1159 mIncludeFileName.push_back(buffer_name.str());
1163 //=======================================================================
1165 void Interpreter::LoadScript( std::string fullPathScriptName,
1166 std::string includeScriptName)
1168 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1170 bool okScriptExist=false;
1171 int iStrScript,sizeVecStricpt=mFileName.size();
1172 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1174 if (mFileName[iStrScript] == fullPathScriptName )
1180 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1181 // if (okScriptExist==true)
1183 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1184 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1189 s = new std::ifstream;
1190 s->open(fullPathScriptName.c_str());
1193 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1197 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1198 << "] found" << std::endl);
1201 mFileName.push_back(fullPathScriptName);
1202 mIncludeFileName.push_back(includeScriptName);
1207 //=======================================================================
1211 void Interpreter::CloseCurrentFile()
1213 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1216 if (mFile.size()==0)
1218 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1222 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1224 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1225 if (file!=0) file->close();
1227 delete mFile.back();
1229 mFileName.pop_back();
1230 mIncludeFileName.pop_back();
1233 bbtkDebugMessage("Interpreter",9," Remains "
1235 <<" open"<<std::endl);
1236 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1239 //=======================================================================
1241 //=======================================================================
1245 void Interpreter::CloseAllFiles()
1247 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1250 while (mFile.size() != 0)
1254 mFile.back()->close();
1255 delete mFile.back();
1257 bbtkDebugMessage("Interpreter",9,
1258 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1259 mFileName.pop_back();
1260 mIncludeFileName.pop_back();
1264 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1267 //=======================================================================
1271 //=======================================================================
1275 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1276 CommandInfoType& info )
1278 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1280 // searches the command category
1281 CommandDictType::iterator c;
1282 c = mCommandDict.find(words[0]);
1283 if ( c == mCommandDict.end() ) {
1284 bbtkError(words[0]<<" : unknown command");
1287 // tests the number of args
1288 if ( ( words.size()-1 < c->second.argmin ) ||
1289 ( words.size()-1 > c->second.argmax ) )
1291 HelpCommand(words[0]);
1292 bbtkError(words[0]<<" : wrong number of arguments");
1296 bbtkDecTab("Interpreter",9);
1298 //=======================================================================
1301 //=======================================================================
1302 /// Displays help on all the commands
1303 void Interpreter::Help(const std::vector<std::string>& words)
1305 unsigned int nbarg = words.size()-1;
1313 if (words[1]=="packages")
1315 GetExecuter()->GetFactory()->PrintPackages(true);
1320 HelpCommand(words[1]);
1322 catch (bbtk::Exception e)
1326 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1330 ConfigurationFile::GetInstance().Get_doc_path();
1331 url += "/bbdoc/" + words[1] + "/index.html";
1332 if (Utilities::FileExists(url))
1334 mUser->InterpreterUserViewHtmlPage(url);
1338 catch (bbtk::Exception f)
1342 std::string package;
1343 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1347 ConfigurationFile::GetInstance().Get_doc_path();
1348 url += "/bbdoc/" + package + "/index.html";
1349 if (Utilities::FileExists(url))
1351 url += "#" + words[1];
1352 mUser->InterpreterUserViewHtmlPage(url);
1356 catch (bbtk::Exception g)
1360 GetExecuter()->ShowRelations(words[1],"0","9999");
1362 catch (bbtk::Exception h){
1363 bbtkError("\""<<words[1].c_str()
1364 <<"\" is not a known command, package, black box type or black box name");
1372 if (words[2]=="all")
1374 if ( words[1]=="packages" )
1376 GetExecuter()->GetFactory()->PrintPackages(true,true);
1381 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1383 catch (bbtk::Exception f)
1389 HelpCommand(words[0]);
1390 bbtkError(words[0]<<" : syntax error");
1395 bbtkError("Should not reach here !!!");
1398 //=======================================================================
1400 //===================================================================
1401 /// Displays the Configuration
1402 void Interpreter::Config() const
1404 ConfigurationFile::GetInstance().GetHelp(1);
1406 //===================================================================
1408 //=======================================================================
1409 /// Displays help on all the commands
1410 void Interpreter::HelpCommands()
1412 std::cout << "Available commands :" << std::endl;
1413 CommandDictType::iterator i;
1414 for ( i = mCommandDict.begin();
1415 i != mCommandDict.end();
1417 std::cout << " " << i->first << std::endl;
1418 // std::cout << " usage : " << i->second.syntax << std::endl;
1419 // std::cout << " " << i->second.help << std::endl;
1423 //=======================================================================
1426 //=======================================================================
1427 /// Displays help on a particular commands
1428 void Interpreter::HelpCommand(const std::string& s)
1430 CommandDictType::iterator c;
1431 c = mCommandDict.find(s);
1432 if ( c == mCommandDict.end() ) {
1433 bbtkError(s<<" : Unknown command");
1435 // std::cout << " " << s << " : "<< std::endl;
1436 // CommandParamDictType::iterator i;
1437 // for ( i = c->second.begin();
1438 // i != c->second.end();
1440 std::cout << " usage : " << c->second.syntax << std::endl;
1441 std::cout << " " << c->second.help << std::endl;
1444 //=======================================================================
1447 //=======================================================================
1448 /// Fills the vector commands with the commands which
1449 /// have the first n chars of buf for prefix
1450 /// TODO : skip initial spaces in buf and also return the position of first
1451 /// non blank char in buf
1452 void Interpreter::FindCommandsWithPrefix( char* buf,
1454 std::vector<std::string>& commands )
1456 CommandDictType::const_iterator i;
1457 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1459 if ((i->first).find(buf,0,n) == 0)
1460 commands.push_back(i->first);
1463 //=======================================================================
1467 //=======================================================================
1468 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1470 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1471 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1473 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1474 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1475 // E.G. STORE THIS IN bbtk_config.xml
1476 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1477 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1478 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1479 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1480 #define BBTK_BACKSPACE_KBCODE 0x00000008
1481 #define BBTK_DEL_KBCODE 0x0000007F
1482 #define BBTK_SPACE_KBCODE 0x00000020
1484 //=======================================================================
1485 void Interpreter::GetLineFromPrompt(std::string& s)
1490 int MAX_LINE_SIZE = 160;
1491 int MAX_HISTORY_SIZE = 100;
1493 char* newline = new char[MAX_LINE_SIZE];
1494 memset(newline,0,MAX_LINE_SIZE);
1495 char* histline = new char[MAX_LINE_SIZE];
1496 memset(histline,0,MAX_LINE_SIZE);
1498 char* line = newline;
1499 int hist = mHistory.size();
1505 read ( STDIN_FILENO, &c, 4) ;
1507 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1509 // Printable character
1510 if ( (ind<MAX_LINE_SIZE-1) &&
1511 ( c >= BBTK_SPACE_KBCODE ) &&
1512 ( c < BBTK_DEL_KBCODE ))
1520 // delete the unused line
1526 // empty lines are not stored in from history
1529 // if history too long : delete oldest command
1530 if (mHistory.size()>MAX_HISTORY_SIZE)
1532 delete mHistory.front();
1533 mHistory.pop_front();
1535 mHistory.push_back(line);
1540 else if ( (ind>0) &&
1541 ((c == BBTK_BACKSPACE_KBCODE) ||
1542 (c == BBTK_DEL_KBCODE)) )
1550 // TODO : Command completion
1551 std::vector<std::string> commands;
1552 FindCommandsWithPrefix( line,ind,commands);
1553 if (commands.size()==1)
1555 std::string com = *commands.begin();
1556 for (; ind<com.size(); ++ind)
1558 PrintChar(com[ind]);
1564 else if (commands.size()>1)
1566 std::vector<std::string>::iterator i;
1568 for (i=commands.begin();i!=commands.end();++i)
1570 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1573 write(STDOUT_FILENO,"\n> ",3);
1574 //for (int j=0;j<ind;++j)
1576 write(STDOUT_FILENO,line,ind);
1580 // Arrow up : back in history
1581 else if (c==BBTK_UP_ARROW_KBCODE)
1585 // erase current line
1586 while (ind--) BackSpace();
1590 strcpy(histline,mHistory[hist]);
1594 write(STDOUT_FILENO,line,ind);
1597 // Arrow down : down in history
1598 else if (c==BBTK_DOWN_ARROW_KBCODE)
1600 if (hist<mHistory.size()-1)
1602 // erase current line
1603 while (ind--) BackSpace();
1607 strcpy(histline,mHistory[hist]);
1611 write(STDOUT_FILENO,line,ind);
1613 // end of history : switch back to newline
1614 else if (hist==mHistory.size()-1)
1616 // erase current line
1617 while (ind--) BackSpace();
1624 write(STDOUT_FILENO,line,ind);
1628 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1630 PrintChar(line[ind]);
1635 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1643 write(STDOUT_FILENO,"\n\r",2);
1651 //=======================================================================
1652 void Interpreter::GetLineFromPrompt(std::string& s)
1678 //=======================================================================
1684 //=======================================================================
1685 void Interpreter::CommandLineInterpreter()
1687 bbtkDebugMessageInc("Interpreter",9,
1688 "Interpreter::CommandLineInterpreter()"<<std::endl);
1690 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1691 // Initialise the tty in non canonical mode with no echo
1692 // oter remembers the previous settings to restore them after
1693 struct termios ter,oter;
1696 ter.c_lflag &= ~ECHO;
1697 ter.c_lflag &= ~ICANON;
1700 tcsetattr(0,TCSANOW,&ter);
1703 mCommandLine = true;
1705 bool insideComment = false; // for multiline comment
1711 GetLineFromPrompt(line);
1712 InterpretLine(line, insideComment);
1714 catch (QuitException e)
1716 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1719 catch (bbtk::Exception e)
1723 catch (std::exception& e)
1725 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1729 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1734 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1735 tcsetattr(0,TCSANOW,&oter);
1738 std::cout << "Good bye !" << std::endl;
1740 bbtkDebugDecTab("Interpreter",9);
1743 //=======================================================================
1744 void Interpreter::Graph(const std::vector<std::string>& words)
1747 bool system_display = true;
1749 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1750 system_display = false;
1752 if (words.size()==1)
1754 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1756 else if (words.size()==2)
1758 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1760 else if (words.size()==3)
1762 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1764 else if (words.size()==4)
1766 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1768 else if (words.size()==5)
1770 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1772 else if (words.size()==6)
1774 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1776 else if (words.size()==7)
1778 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1781 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1782 mUser->InterpreterUserViewHtmlPage(page);
1785 //=======================================================================
1788 //=======================================================================
1789 void Interpreter::Index(const std::string& filename,
1790 const std::string& type)
1792 Factory::IndexEntryType t;
1793 if (type=="Initials") t = Factory::Initials;
1794 else if (type=="Categories") t = Factory::Categories;
1795 else if (type=="Packages") t = Factory::Packages;
1796 else if (type=="Adaptors") t = Factory::Adaptors;
1798 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1800 //=======================================================================