1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/25 06:22:53 $
7 Version: $Revision: 1.53 $
9 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10 l'Image). All rights reserved. See Doc/License.txt or
11 http://www.creatis.insa-lyon.fr/Public/bbtk/License.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
20 * \brief class Interpreter :
23 #include "bbtkInterpreter.h"
24 #include "bbtkMessageManager.h"
25 #include "bbtkConfigurationFile.h"
26 #include "bbtkUtilities.h"
29 #ifdef CMAKE_HAVE_TERMIOS_H
31 #define BBTK_USE_TERMIOS_BASED_PROMPT
39 //Interpreter* Interpreter::mGlobalInterpreter = NULL;
41 //=======================================================================
45 Interpreter::Interpreter()
52 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
53 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
54 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
56 mExecuter = new bbtk::Executer();
57 mExecuter->SetInterpreter(this);
59 // For the time being, comment out previous line, and
60 // uncomment next line to check Transcriptor
62 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
64 // Builds the commands dict
67 info.category = "new";
71 info.syntax = "new <type> <name>";
72 info.help = "Creates a new black box of type <type> with name <name>";
73 mCommandDict[info.category] = info;
75 info.category = "delete";
79 info.syntax = "delete <box>";
80 info.help = "Deletes the black box of name <box>";
81 mCommandDict[info.category] = info;
83 info.category = "connect";
87 info.syntax = "connect <box1.output> <box2.input>";
88 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
89 mCommandDict[info.category] = info;
91 info.category = "print";
95 info.syntax = "print <string>";
96 info.help = "Prints the string. Substitutes any token of the form '$box.output$' by the string adaptation of the output of the box (requires the right adaptor). No carriage return is issued at the end, use '\\n' to add carriage returns. The level of 'Echo' messages must be greater than 1 (see the command 'message').";
97 mCommandDict[info.category] = info;
99 info.category = "exec";
103 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
104 info.help = "Executes the black box of name <box> (and connected boxes if needed). If the special category 'freeze' is given then freezes any further execution command. 'unfreeze' reverts to normal execution mode.";
105 mCommandDict[info.category] = info;
107 info.category = "package";
110 info.code = cPackage;
111 info.syntax = "package <name>";
112 info.help = "Begins the definition of a package.";
113 mCommandDict[info.category] = info;
115 info.category = "endpackage";
118 info.code = cEndPackage;
119 info.syntax = "endpackage";
120 info.help = "Ends the definition of a package.";
121 mCommandDict[info.category] = info;
123 info.category = "define";
127 info.syntax = "define <type> [<package>]";
128 info.help = "Begins the definition of a new type of complex black box called <type>. If <package> if provided will create it in the given package.";
129 mCommandDict[info.category] = info;
131 info.category = "endefine";
134 info.code = cEndDefine;
135 info.syntax = "endefine";
136 info.help = "Ends the definition of a new type of complex black box";
137 mCommandDict[info.category] = info;
139 info.category = "input";
143 info.syntax = "input <name> <box.input> <help>";
144 info.help = "Defines the input <name> of the current working black box as being an alias for the input <input> of the black box <box>. <help> defines the help string for the newly created input";
145 mCommandDict[info.category] = info;
147 info.category = "output";
151 info.syntax = "output <name> <box.output> <help>";
152 info.help = "Defines the output <name> of the current working black box as being an alias for the output <output> of the black box <box>. <help> defines the help string for the newly created output";
153 mCommandDict[info.category] = info;
155 info.category = "set";
159 info.syntax = "set <box.input> <value>";
160 info.help = "Sets the value of the input <input> of the black box <box> to <value>. There must exist a string to the value type adaptor";
161 mCommandDict[info.category] = info;
163 info.category = "config"; // JPR
167 info.syntax = "config";
168 info.help = "Prints the value of all configuration parameters";
169 mCommandDict[info.category] = info;
171 info.category = "index"; // LG
176 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
177 info.help = "Creates an html index of known boxes. If filename is provided then save it to the file 'filename'. The default index entries are the initial letters of the names of the boxes. If 'Packages' or 'Categories' is provided then the entries are either the packages names or the categories. If 'Adaptors' is provided then an alphabetical index of all adaptors is created.";
178 mCommandDict[info.category] = info;
180 info.category = "reset";
184 info.syntax = "reset";
185 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
186 mCommandDict[info.category] = info;
188 info.category = "author";
192 info.syntax = "author <string>";
193 info.help = "Adds the string <string> to the author information of the black box being defined";
194 mCommandDict[info.category] = info;
196 info.category = "category"; //JP
199 info.code = cCategory;
200 info.syntax = "category <list of items, separated by ;>";
201 info.help = "Adds the string <string> to the category information of the black box being defined";
202 mCommandDict[info.category] = info;
204 info.category = "description";
207 info.code = cDescription;
208 info.syntax = "description <string>";
209 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
210 mCommandDict[info.category] = info;
212 info.category = "help";
216 info.syntax = "help";
217 info.syntax = "\n (1) help \n (2) help <command name> \n (3) help packages [all]\n (4) help <package name> [all]\n (5) help <black box type> \n (6) help <black box name>";
218 info.help = "Effect :\n (1) Lists all available commands;\n (2) Prints help on a particular command; \n (3) Lists the packages loaded and their black boxes.\n Add 'all' to list adaptors; \n (4) Prints short help on the black boxes of a package.\n Add 'all' to include adaptors; \n (5) Prints full help on a black box type; \n (6) Prints information on the inputs, outputs and connections of a black box instance.";
219 mCommandDict[info.category] = info;
221 info.category = "message";
224 info.code = cMessage;
225 info.syntax = "message <kind> <level>";
226 info.help = "Sets the level of the kind of messages <kind> to <level>.\n If kind='All' then sets the level for all kinds. If no kind nor level is passed then prints info on available kinds of messages and their current level."; mCommandDict[info.category] = info;
228 info.category = "include";
231 info.code = cInclude;
232 info.syntax = "include <filename> [source]";
233 info.help = "Includes the file <filename>.\n 'source' : If the keyword 'source' is provided then informs bbi that the included file is the source of the current box definition (Advanced; used to get the right 'Include' field in html doc of packages 'appli' scripts).";
234 mCommandDict[info.category] = info;
236 info.category = "quit";
240 info.syntax = "quit";
241 info.help = "Quits the program (during script execution it stops the complete execution)";
242 mCommandDict[info.category] = info;
244 info.category = "load";
248 info.syntax = "load <packagename>";
249 info.help = "Loads the black box package <packagename>";
250 mCommandDict[info.category] = info;
252 info.category = "unload";
256 info.syntax = "unload <packagename>";
257 info.help = "Unloads the black box package <packagename>";
258 mCommandDict[info.category] = info;
260 info.category = "graph";
264 info.syntax = "graph [ BlackBoxName [ Detail 0..1 [ Level 0..99999 [ Output html file [ Custom header [ Custom title ]]]]]] \n graph [ BlackBoxNameType [ Detail 0..1 [ Level 0..99999 [ Output html file [ Custom header [ Custom title ]]]]]]";
265 info.help = "Shows a graphical view of a bbtk pipeline.\n- BlackBoxName : name of the box to view. Default '.' : current box.\n- BlackBoxNameType : name of the type of box to view, ex : 'workspace')";
266 mCommandDict[info.category] = info;
269 info.category = "workspace";
272 info.code = cWorkspace;
273 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
274 info.help = "Configures the workspace.\n 'freeze' allow to block execution commands while keeping definition commands active. 'unfreeze' turns back the worspace in 'normal' mode.\n 'rename' allow to set a new name to the workspace.";
275 mCommandDict[info.category] = info;
278 bbtkDebugDecTab("Interpreter",9);
281 //=======================================================================
285 //=======================================================================
289 Interpreter::~Interpreter()
291 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
294 bbtkDebugDecTab("Interpreter",9);
296 //=======================================================================
299 InterpreterError::InterpreterError( const std::string& message,
301 const std::string& script_file,
304 : Exception("Interpreter",0,message),
305 mInScriptFile(in_script_file),
306 mScriptFile(script_file),
307 mScriptLine(script_line)
310 InterpreterError::InterpreterError( const Exception& excep,
312 const std::string& script_file,
316 mInScriptFile(in_script_file),
317 mScriptFile(script_file),
318 mScriptLine(script_line)
321 //=======================================================================
322 void Interpreter::CatchBbtkException( const bbtk::Exception& e )
326 bool in_script = false;
327 std::string file("");
329 if (mFileName.size()) {
330 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
331 if (fs!=0) in_script = true;
332 file = mFileName.back();
335 throw InterpreterError(e,in_script,file,line);
339 std::stringstream mess;
340 mess << "* ERROR : "<<e.GetMessage()<<std::endl;
341 if (mFileName.size()) {
342 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
343 mess << "* LINE : "<<mLine.back()<<std::endl;
345 std::cerr << mess.str();
348 //=======================================================================
350 //=======================================================================
351 void Interpreter::CatchStdException( const std::exception& e )
355 bool in_script = false;
356 std::string file("");
358 if (mFileName.size()) {
359 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
360 if (fs!=0) in_script = true;
361 file = mFileName.back();
364 throw InterpreterError(e.what(),in_script,file,line);
368 std::stringstream mess;
369 mess << "* ERROR : "<<e.what()<<std::endl;
370 if (mFileName.size()) {
371 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
372 mess << "* LINE : "<<mLine.back()<<std::endl;
374 std::cerr << mess.str();
377 //=======================================================================
379 //=======================================================================
380 void Interpreter::CatchUnknownException()
384 bool in_script = false;
385 std::string file("");
387 if (mFileName.size()) {
388 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
389 if (fs!=0) in_script = true;
390 file = mFileName.back();
393 throw InterpreterError("Unknown exception caught",
394 in_script,file,line);
398 std::stringstream mess;
399 mess << "* UNDEFINED ERROR (not a bbtk nor a std exception)"
401 if (mFileName.size()) {
402 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
403 mess << "* LINE : "<<mLine.back()<<std::endl;
405 std::cerr << mess.str();
408 //=======================================================================
410 //=======================================================================
412 #define CATCH_MACRO \
413 catch (QuitException e) \
415 status = Interpreter_QUIT; \
416 if (mThrow) throw QuitException(); \
418 catch (bbtk::Exception e) \
420 status = Interpreter_ERROR; \
421 CatchBbtkException(e); \
423 catch (std::exception& e) \
425 status = Interpreter_ERROR; \
426 CatchStdException(e); \
430 status = Interpreter_ERROR; \
431 CatchUnknownException(); \
433 //=======================================================================
436 //=======================================================================
440 Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
442 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
444 bool exm = mCommandLine;
445 mCommandLine = false;
447 ExitStatus status = Interpreter_OK;
451 SwitchToFile(filename);
453 bool insideComment = false; // for multiline comment
454 while (mFile.size()>0)
456 while (!mFile.back()->eof()) {
459 mFile.back()->getline(buf,500);
460 std::string str(buf);
461 int size=str.length();
462 if ( str[ size-1 ]==13 )
467 InterpretLine(str, insideComment);
476 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
477 bbtkDecTab("Interpreter",9);
483 //=======================================================================
486 //=======================================================================
490 Interpreter::ExitStatus
491 Interpreter::InterpretBuffer( std::stringstream* buffer )
493 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
495 bool exm = mCommandLine;
496 mCommandLine = false;
498 ExitStatus status = Interpreter_OK;
502 SwitchToStream(buffer);
503 bool insideComment = false; // for multiline comment
504 while (mFile.size()>0)
506 while (!mFile.back()->eof()) {
509 mFile.back()->getline(buf,500);
510 std::string str(buf);
512 int size=str.length();
513 if ( str[ size-1 ]==13 )
518 InterpretLine(str, insideComment);
528 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
529 bbtkDecTab("Interpreter",9);
534 //=======================================================================
536 //=======================================================================
537 /// Runs the interpretation of a command
538 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
540 printf("EED Interpreter::InterpretLine %s \n", line.c_str() );
541 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
543 ExitStatus status = Interpreter_OK;
547 bool insideComment = false;
548 InterpretLine(line, insideComment);
552 catch (QuitException e)
554 status = Interpreter_QUIT;
556 catch (bbtk::Exception e)
558 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
559 status = Interpreter_ERROR;
561 catch (std::exception& e)
563 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
564 status = Interpreter_ERROR;
569 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
570 status = Interpreter_ERROR;
574 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
576 bbtkDecTab("Interpreter",9);
582 //=======================================================================
586 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
588 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
589 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
591 std::vector<std::string> words;
592 SplitLine(line,words);
597 bbtkDebugDecTab("Interpreter",9);
601 // Single line comment : # or //
602 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
604 bbtkDebugDecTab("Interpreter",9);
605 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
609 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
611 if (words[0][0]=='/' && words[0][1]=='*')
613 bbtkDebugDecTab("Interpreter",9);
614 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
615 insideComment = true;
619 if (words[0][0]=='*' && words[0][1]=='/')
621 bbtkDebugDecTab("Interpreter",9);
622 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
623 if ( !insideComment ) {
624 bbtkDebugDecTab("Interpreter",9);
625 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
627 insideComment = false;
633 bbtkDebugDecTab("Interpreter",9);
634 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
639 CommandInfoType command;
640 InterpretCommand(words,command);
642 bbtkDebugMessage("Interpreter",9,
643 "Command='"<<command.category
644 <<"' code="<<command.code<<std::endl);
646 std::string left,right,left2,right2;
647 std::string filename;
648 switch (command.code)
651 mExecuter->Create(words[1],words[2]);
656 // mExecuter->Remove(words[1]);
660 Utilities::SplitAroundFirstDot(words[1],left,right);
661 Utilities::SplitAroundFirstDot(words[2],left2,right2);
662 mExecuter->Connect(left,right,left2,right2);
666 mExecuter->BeginPackage(words[1]);
670 mExecuter->EndPackage();
674 if (mFileName.size()>0)
676 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
680 mExecuter->Define(words[1],"",filename);
684 mExecuter->Define(words[1],words[2],filename);
689 mExecuter->EndDefine();
693 Print(words[1]); /// \todo use generate command
697 if (words[1]=="freeze")
698 mExecuter->SetNoExecMode(true);
699 else if (words[1]=="unfreeze")
700 mExecuter->SetNoExecMode(false);
702 mExecuter->Update(words[1]);
706 Utilities::SplitAroundFirstDot(words[2],left,right);
707 mExecuter->DefineInput(words[1],left,right,words[3]);
711 Utilities::SplitAroundFirstDot(words[2],left,right);
712 mExecuter->DefineOutput(words[1],left,right,words[3]);
716 Utilities::SplitAroundFirstDot(words[1],left,right);
717 mExecuter->Set(left,right,words[2]);
721 mExecuter->Author(words[1]);
725 mExecuter->Category(words[1]);
730 Index("tmp_index.html");
731 else if (words.size()==2)
733 else if (words.size()==3)
734 Index(words[1],words[2]);
738 mExecuter->Description(words[1]);
748 bbtk::MessageManager::PrintInfo();
752 sscanf(words[2].c_str(),"%d",&level);
753 bbtk::MessageManager::SetMessageLevel(words[1],level);
766 this->mExecuter->Reset();
772 InterpretFile(words[1]);
776 SwitchToFile(words[1]);
778 // if 'source' was given
781 GetExecuter()->SetCurrentFileName(words[1]);
786 GetExecuter()->GetFactory()->LoadPackage(words[1]);
790 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
795 throw QuitException();
799 if (words.size() == 2)
801 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
802 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
806 mExecuter->SetWorkspaceName(words[2]);
811 bbtkInternalError("should not reach here !!!");
814 bbtkDecTab("Interpreter",9);
816 //=======================================================================
822 //=======================================================================
826 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
828 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
830 std::string delimiters = "\"";
831 std::vector<std::string> quote;
832 Utilities::SplitString(str,delimiters,quote);
835 std::vector<std::string>::iterator i;
836 for (i=quote.begin(); i!=quote.end(); )
838 Utilities::SplitString(*i,delimiters,tokens);
842 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
843 tokens.push_back(*i);
848 for (i=tokens.begin(); i!=tokens.end(); ++i)
850 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
852 bbtkDebugMessageCont("Interpreter",9,std::endl);
854 bbtkDebugDecTab("Interpreter",9);
856 //=======================================================================
859 //=======================================================================
860 // Replaces substrings "\\n" by a real carriage return "\n"
861 void SubsBackslashN ( std::string& s )
863 std::string ss("\\n");
864 std::string::size_type pos = 0;
867 while ( pos != std::string::npos )
869 s.replace(pos,2,cr,1);
870 pos = s.find(ss, pos-1);
873 //=======================================================================
876 //=======================================================================
880 void Interpreter::Print( const std::string& str)
882 if (mExecuter->GetNoExecMode()) return;
884 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
887 // InterpretLine ("load std")
888 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
889 // InterpretLine("new Print _P_")
890 // InterpretLine("connect _C_.Out _P_.In")
894 std::vector<std::string> chains;
895 std::string delimiters("$");
897 // Skip delimiters at beginning.
898 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
900 if (lastPos>0) is_text = false;
902 // Find first delimiter.
903 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
905 while (std::string::npos != pos || std::string::npos != lastPos)
909 // Found a text token, add it to the vector.
910 chains.push_back(str.substr(lastPos, pos - lastPos));
911 // std::string token = str.substr(lastPos, pos - lastPos)
912 // InterpretLine("set _C_.In%num% %token%")
918 // is an output (between $$) : decode
919 std::string tok,box,output;
920 tok = str.substr(lastPos, pos - lastPos);
921 Utilities::SplitAroundFirstDot(tok,box,output);
922 chains.push_back( mExecuter->Get(box,output) );
924 // InterpretLine("connect %tok% _C_.In%num%")
927 // Skip delimiters. Note the "not_of"
928 lastPos = str.find_first_not_of(delimiters, pos);
929 // Find next delimiter
930 pos = str.find_first_of(delimiters, lastPos);
935 // InterpretLine("exec _P_")
936 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
938 std::vector<std::string>::iterator i;
939 for (i= chains.begin(); i!=chains.end(); ++i)
941 // bbtkMessage("Echo",1,*i);
945 std::cout << std::endl;
946 bbtkDebugDecTab("Interpreter",9);
949 //=======================================================================
954 // ===================================================================================
956 void Interpreter::SwitchToFile( const std::string& name )
958 // Note : in the following :
959 // name : the user supplied name
960 // - abreviated name e.g. scr scr.bbs
961 // - relative full name e.g. ./scr.bbs ../../scr.bbs
962 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
963 // same for Windows, with c:, d: ...
965 // use ./directory/subdir/scrname.bbs
968 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
969 <<name<<"\")"<<std::endl);
971 std::vector<std::string> script_paths;
972 std::string fullPathScriptName; // full path script name
973 std::string pkgname; // e.g. <scriptname>.bbs
974 std::vector<std::string> Filenames;
976 // The following is *NOT* a debug time message :
977 // It's a user intended message.
978 // Please don't remove it.
979 bbtkMessage("Interpreter",1,
980 "look for : [" << name
981 << "]" << std::endl);
982 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
985 pkgname = Utilities::ExtractScriptName(name,upath);
987 bbtkMessage("Interpreter",1,
988 "extract : pkgname [" << pkgname
989 << "] upath [" << upath << "]" << std::endl);
990 bool fullnameGiven = false;
991 bool foundFile = false;
993 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
997 std::stringstream* stream = new std::stringstream;
998 //if (upath.size()!=0) // avoid troubles for "*"
1000 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
1002 int nbFiles = Utilities::Explore(upath, false, Filenames);
1004 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1006 int lgr = (*i).size();
1008 continue; // ignore non .bbs file
1009 if ((*i).substr(lgr-4, 4) != ".bbs")
1012 printf("EED Interpreter::SwitchToFile flag01 %s \n", (*i).c_str() );
1013 (*stream) << "include \"" << *i << "\"\n";
1018 bbtkMessage("Interpreter",2,
1019 "WARNING : No '.bbs' file found in ["
1020 << upath << "]" << std::endl);
1022 SwitchToStream(stream);
1028 std::vector<std::string>::iterator i;
1029 std::string fullDirectoryName;
1030 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1034 // we *really* want '.' to be the current working directory
1036 char buf[2048]; // for getcwd
1037 char * currentDir = getcwd(buf, 2048);
1038 std::string cwd(currentDir);
1042 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
1044 // without last slash "\"
1045 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
1047 // Check if library exists
1048 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
1050 // The following is *NOT* a debug time message :
1051 // It's a user intended message.
1052 // Please don't remove it.
1053 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
1054 <<"] : doesn't exist" <<std::endl);
1055 continue; // try next path
1060 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
1063 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
1065 int lgr = (*i).size();
1067 continue; // ignore non .bbs file
1068 if ((*i).substr(lgr-4, 4) != ".bbs")
1071 printf("EED Interpreter::SwitchToFile flag02 %s \n", (*i).c_str() );
1072 (*stream) << "include \"" << *i << "\"\n";
1077 bbtkMessage("Interpreter",1,
1078 "WARNING : No '.bbs' file found in ["
1079 << fullDirectoryName << "]" << std::endl);
1081 SwitchToStream(stream);
1084 //break; // a directory was found; we stop iterating
1085 // LG : No! We want all files included !
1090 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1091 // (not only a plain script name)
1092 // we trust him, and try to expland the directory name
1093 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1095 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1098 // ===========================================================check user supplied location
1099 fullnameGiven = true;
1101 fullPathScriptName = Utilities::ExpandLibName(name, false);
1103 // allow user to always forget ".bbs"
1104 int l = fullPathScriptName.size();
1110 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1112 fullPathScriptName = fullPathScriptName + ".bbs";
1117 fullPathScriptName = fullPathScriptName + ".bbs";
1120 if ( Utilities::FileExists(fullPathScriptName))
1127 // =============================================================== iterate on the paths
1130 std::vector<std::string>::iterator i;
1131 for (i=script_paths.begin();i!=script_paths.end();++i)
1134 // we *really* want '.' to be the current working directory
1136 char buf[2048]; // for getcwd
1137 char * currentDir = getcwd(buf, 2048);
1138 std::string cwd(currentDir);
1142 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1144 // Check if library exists
1145 if ( ! Utilities::FileExists(fullPathScriptName) )
1147 // The following is *NOT* a debug time message :
1148 // It's a user intended message.
1149 // Please don't remove it.
1150 bbtkMessage("Interpreter",2,
1151 " [" <<fullPathScriptName <<"] : doesn't exist"
1153 continue; // try next path
1155 bbtkMessage("Interpreter",2,
1156 " [" <<fullPathScriptName
1157 <<"] : found" <<std::endl);
1159 break; // a script was found; we stop iterating
1161 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1167 if(fullPathScriptName == "")
1168 bbtkError("Path ["<<upath<<"] doesn't exist");
1170 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1172 bbtkError("No ["<<pkgname<<".bbs] script found");
1176 LoadScript(fullPathScriptName,name);
1182 void Interpreter::SwitchToStream( std::stringstream* stream )
1184 mFile.push_back(stream);
1185 std::ostringstream buffer_name;
1187 buffer_name << "buffer_" ;
1189 if (mFileName.size()>0 )
1191 buffer_name << mFileName.back() << "_" << mLine.back();
1193 mFileName.push_back(buffer_name.str());
1194 mIncludeFileName.push_back(buffer_name.str());
1198 //=======================================================================
1200 void Interpreter::LoadScript( std::string fullPathScriptName,
1201 std::string includeScriptName)
1203 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1205 bool okScriptExist=false;
1206 int iStrScript,sizeVecStricpt=mFileName.size();
1207 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1209 if (mFileName[iStrScript] == fullPathScriptName )
1215 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1216 // if (okScriptExist==true)
1218 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1219 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1224 s = new std::ifstream;
1225 s->open(fullPathScriptName.c_str());
1228 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1232 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1233 << "] found" << std::endl);
1236 mFileName.push_back(fullPathScriptName);
1237 mIncludeFileName.push_back(includeScriptName);
1243 //=======================================================================
1247 void Interpreter::CloseCurrentFile()
1249 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1252 if (mFile.size()==0)
1254 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1258 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1260 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1261 if (file!=0) file->close();
1263 delete mFile.back();
1265 mFileName.pop_back();
1266 mIncludeFileName.pop_back();
1269 bbtkDebugMessage("Interpreter",9," Remains "
1271 <<" open"<<std::endl);
1272 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1275 //=======================================================================
1277 //=======================================================================
1281 void Interpreter::CloseAllFiles()
1283 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1286 while (mFile.size() != 0)
1290 mFile.back()->close();
1291 delete mFile.back();
1293 bbtkDebugMessage("Interpreter",9,
1294 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1295 mFileName.pop_back();
1296 mIncludeFileName.pop_back();
1300 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1303 //=======================================================================
1307 //=======================================================================
1311 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1312 CommandInfoType& info )
1314 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1316 // searches the command category
1317 CommandDictType::iterator c;
1318 c = mCommandDict.find(words[0]);
1319 if ( c == mCommandDict.end() ) {
1320 bbtkError(words[0]<<" : unknown command");
1323 // tests the number of args
1324 if ( ( words.size()-1 < c->second.argmin ) ||
1325 ( words.size()-1 > c->second.argmax ) )
1327 HelpCommand(words[0]);
1328 bbtkError(words[0]<<" : wrong number of arguments");
1332 bbtkDecTab("Interpreter",9);
1334 //=======================================================================
1337 //=======================================================================
1338 /// Displays help on all the commands
1339 void Interpreter::Help(const std::vector<std::string>& words)
1341 unsigned int nbarg = words.size()-1;
1349 if (words[1]=="packages")
1351 GetExecuter()->GetFactory()->PrintPackages(true);
1356 HelpCommand(words[1]);
1358 catch (bbtk::Exception e)
1362 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1366 ConfigurationFile::GetInstance().Get_doc_path();
1367 url += "/bbdoc/" + words[1] + "/index.html";
1368 if (Utilities::FileExists(url))
1370 mUser->InterpreterUserViewHtmlPage(url);
1374 catch (bbtk::Exception f)
1378 std::string package;
1379 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1383 ConfigurationFile::GetInstance().Get_doc_path();
1384 url += "/bbdoc/" + package + "/index.html";
1385 if (Utilities::FileExists(url))
1387 url += "#" + words[1];
1388 mUser->InterpreterUserViewHtmlPage(url);
1392 catch (bbtk::Exception g)
1396 GetExecuter()->ShowRelations(words[1],"0","9999");
1398 catch (bbtk::Exception h){
1399 bbtkError("\""<<words[1].c_str()
1400 <<"\" is not a known command, package, black box type or black box name");
1408 if (words[2]=="all")
1410 if ( words[1]=="packages" )
1412 GetExecuter()->GetFactory()->PrintPackages(true,true);
1417 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1419 catch (bbtk::Exception f)
1425 HelpCommand(words[0]);
1426 bbtkError(words[0]<<" : syntax error");
1431 bbtkError("Should not reach here !!!");
1434 //=======================================================================
1436 //===================================================================
1437 /// Displays the Configuration
1438 void Interpreter::Config() const
1440 ConfigurationFile::GetInstance().GetHelp(1);
1442 //===================================================================
1444 //=======================================================================
1445 /// Displays help on all the commands
1446 void Interpreter::HelpCommands()
1448 std::cout << "Available commands :" << std::endl;
1449 CommandDictType::iterator i;
1450 for ( i = mCommandDict.begin();
1451 i != mCommandDict.end();
1453 std::cout << " " << i->first << std::endl;
1454 // std::cout << " usage : " << i->second.syntax << std::endl;
1455 // std::cout << " " << i->second.help << std::endl;
1459 //=======================================================================
1462 //=======================================================================
1463 /// Displays help on a particular commands
1464 void Interpreter::HelpCommand(const std::string& s)
1466 CommandDictType::iterator c;
1467 c = mCommandDict.find(s);
1468 if ( c == mCommandDict.end() ) {
1469 bbtkError(s<<" : Unknown command");
1471 // std::cout << " " << s << " : "<< std::endl;
1472 // CommandParamDictType::iterator i;
1473 // for ( i = c->second.begin();
1474 // i != c->second.end();
1476 std::cout << " usage : " << c->second.syntax << std::endl;
1477 std::cout << " " << c->second.help << std::endl;
1480 //=======================================================================
1483 //=======================================================================
1484 /// Fills the vector commands with the commands which
1485 /// have the first n chars of buf for prefix
1486 /// TODO : skip initial spaces in buf and also return the position of first
1487 /// non blank char in buf
1488 void Interpreter::FindCommandsWithPrefix( char* buf,
1490 std::vector<std::string>& commands )
1492 CommandDictType::const_iterator i;
1493 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1495 if ((i->first).find(buf,0,n) == 0)
1496 commands.push_back(i->first);
1499 //=======================================================================
1503 //=======================================================================
1504 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1506 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1507 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1509 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1510 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1511 // E.G. STORE THIS IN bbtk_config.xml
1512 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1513 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1514 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1515 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1516 #define BBTK_BACKSPACE_KBCODE 0x00000008
1517 #define BBTK_DEL_KBCODE 0x0000007F
1518 #define BBTK_SPACE_KBCODE 0x00000020
1520 //=======================================================================
1521 void Interpreter::GetLineFromPrompt(std::string& s)
1526 int MAX_LINE_SIZE = 160;
1527 int MAX_HISTORY_SIZE = 100;
1529 char* newline = new char[MAX_LINE_SIZE];
1530 memset(newline,0,MAX_LINE_SIZE);
1531 char* histline = new char[MAX_LINE_SIZE];
1532 memset(histline,0,MAX_LINE_SIZE);
1534 char* line = newline;
1535 int hist = mHistory.size();
1541 read ( STDIN_FILENO, &c, 4) ;
1543 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1545 // Printable character
1546 if ( (ind<MAX_LINE_SIZE-1) &&
1547 ( c >= BBTK_SPACE_KBCODE ) &&
1548 ( c < BBTK_DEL_KBCODE ))
1556 // delete the unused line
1562 // empty lines are not stored in from history
1565 // if history too long : delete oldest command
1566 if (mHistory.size()>MAX_HISTORY_SIZE)
1568 delete mHistory.front();
1569 mHistory.pop_front();
1571 mHistory.push_back(line);
1576 else if ( (ind>0) &&
1577 ((c == BBTK_BACKSPACE_KBCODE) ||
1578 (c == BBTK_DEL_KBCODE)) )
1586 // TODO : Command completion
1587 std::vector<std::string> commands;
1588 FindCommandsWithPrefix( line,ind,commands);
1589 if (commands.size()==1)
1591 std::string com = *commands.begin();
1592 for (; ind<com.size(); ++ind)
1594 PrintChar(com[ind]);
1600 else if (commands.size()>1)
1602 std::vector<std::string>::iterator i;
1604 for (i=commands.begin();i!=commands.end();++i)
1606 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1609 write(STDOUT_FILENO,"\n> ",3);
1610 //for (int j=0;j<ind;++j)
1612 write(STDOUT_FILENO,line,ind);
1616 // Arrow up : back in history
1617 else if (c==BBTK_UP_ARROW_KBCODE)
1621 // erase current line
1622 while (ind--) BackSpace();
1626 strcpy(histline,mHistory[hist]);
1630 write(STDOUT_FILENO,line,ind);
1633 // Arrow down : down in history
1634 else if (c==BBTK_DOWN_ARROW_KBCODE)
1636 if (hist<mHistory.size()-1)
1638 // erase current line
1639 while (ind--) BackSpace();
1643 strcpy(histline,mHistory[hist]);
1647 write(STDOUT_FILENO,line,ind);
1649 // end of history : switch back to newline
1650 else if (hist==mHistory.size()-1)
1652 // erase current line
1653 while (ind--) BackSpace();
1660 write(STDOUT_FILENO,line,ind);
1664 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1666 PrintChar(line[ind]);
1671 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1679 write(STDOUT_FILENO,"\n\r",2);
1687 //=======================================================================
1688 void Interpreter::GetLineFromPrompt(std::string& s)
1714 //=======================================================================
1720 //=======================================================================
1721 void Interpreter::CommandLineInterpreter()
1723 bbtkDebugMessageInc("Interpreter",9,
1724 "Interpreter::CommandLineInterpreter()"<<std::endl);
1726 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1727 // Initialise the tty in non canonical mode with no echo
1728 // oter remembers the previous settings to restore them after
1729 struct termios ter,oter;
1732 ter.c_lflag &= ~ECHO;
1733 ter.c_lflag &= ~ICANON;
1736 tcsetattr(0,TCSANOW,&ter);
1739 mCommandLine = true;
1741 bool insideComment = false; // for multiline comment
1747 GetLineFromPrompt(line);
1748 InterpretLine(line, insideComment);
1750 catch (QuitException e)
1752 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1755 catch (bbtk::Exception e)
1759 catch (std::exception& e)
1761 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1765 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1770 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1771 tcsetattr(0,TCSANOW,&oter);
1774 std::cout << "Good bye !" << std::endl;
1776 bbtkDebugDecTab("Interpreter",9);
1779 //=======================================================================
1780 void Interpreter::Graph(const std::vector<std::string>& words)
1783 bool system_display = true;
1785 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1786 system_display = false;
1788 if (words.size()==1)
1790 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1792 else if (words.size()==2)
1794 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1796 else if (words.size()==3)
1798 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1800 else if (words.size()==4)
1802 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1804 else if (words.size()==5)
1806 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1808 else if (words.size()==6)
1810 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1812 else if (words.size()==7)
1814 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1817 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1818 mUser->InterpreterUserViewHtmlPage(page);
1821 //=======================================================================
1824 //=======================================================================
1825 void Interpreter::Index(const std::string& filename,
1826 const std::string& type)
1828 Factory::IndexEntryType t;
1829 if (type=="Initials") t = Factory::Initials;
1830 else if (type=="Categories") t = Factory::Categories;
1831 else if (type=="Packages") t = Factory::Packages;
1832 else if (type=="Adaptors") t = Factory::Adaptors;
1834 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1836 //=======================================================================