1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/26 14:47:36 $
7 Version: $Revision: 1.57 $
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 "bbtkExecuter.h"
25 #include "bbtkTranscriptor.h"
26 #include "bbtkMessageManager.h"
27 #include "bbtkConfigurationFile.h"
28 #include "bbtkUtilities.h"
31 #ifdef CMAKE_HAVE_TERMIOS_H
33 #define BBTK_USE_TERMIOS_BASED_PROMPT
41 //Interpreter* Interpreter::mGlobalInterpreter = NULL;
43 //=======================================================================
47 Interpreter::Interpreter(const std::string& cpp_file)
54 bbtk::MessageManager::RegisterMessageType("Echo","Level>0 : Prints the 'echo' commands of the user.\n\tLevel>1 : Prints the command being interpreted",1);
55 bbtk::MessageManager::RegisterMessageType("Interpreter","Messages of the interpreter",0);
56 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Interpreter()" <<std::endl);
58 if (cpp_file.size()!=0)
60 mExecuter = new bbtk::Transcriptor(cpp_file);
64 mExecuter = new bbtk::Executer();
66 mExecuter->SetInterpreter(this);
68 // For the time being, comment out previous line, and
69 // uncomment next line to check Transcriptor
71 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
73 // Builds the commands dict
76 info.category = "new";
80 info.syntax = "new <type> <name>";
81 info.help = "Creates a new black box of type <type> with name <name>";
82 mCommandDict[info.category] = info;
84 info.category = "delete";
88 info.syntax = "delete <box>";
89 info.help = "Deletes the black box of name <box>";
90 mCommandDict[info.category] = info;
92 info.category = "connect";
96 info.syntax = "connect <box1.output> <box2.input>";
97 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
98 mCommandDict[info.category] = info;
100 info.category = "print";
104 info.syntax = "print <string>";
105 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').";
106 mCommandDict[info.category] = info;
108 info.category = "exec";
112 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
113 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.";
114 mCommandDict[info.category] = info;
116 info.category = "package";
119 info.code = cPackage;
120 info.syntax = "package <name>";
121 info.help = "Begins the definition of a package.";
122 mCommandDict[info.category] = info;
124 info.category = "endpackage";
127 info.code = cEndPackage;
128 info.syntax = "endpackage";
129 info.help = "Ends the definition of a package.";
130 mCommandDict[info.category] = info;
132 info.category = "define";
136 info.syntax = "define <type> [<package>]";
137 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.";
138 mCommandDict[info.category] = info;
140 info.category = "endefine";
143 info.code = cEndDefine;
144 info.syntax = "endefine";
145 info.help = "Ends the definition of a new type of complex black box";
146 mCommandDict[info.category] = info;
148 info.category = "input";
152 info.syntax = "input <name> <box.input> <help>";
153 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";
154 mCommandDict[info.category] = info;
156 info.category = "output";
160 info.syntax = "output <name> <box.output> <help>";
161 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";
162 mCommandDict[info.category] = info;
164 info.category = "set";
168 info.syntax = "set <box.input> <value>";
169 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";
170 mCommandDict[info.category] = info;
172 info.category = "config"; // JPR
176 info.syntax = "config";
177 info.help = "Prints the value of all configuration parameters";
178 mCommandDict[info.category] = info;
180 info.category = "index"; // LG
185 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
186 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.";
187 mCommandDict[info.category] = info;
189 info.category = "reset";
193 info.syntax = "reset";
194 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
195 mCommandDict[info.category] = info;
197 info.category = "author";
201 info.syntax = "author <string>";
202 info.help = "Adds the string <string> to the author information of the black box being defined";
203 mCommandDict[info.category] = info;
205 info.category = "category"; //JP
208 info.code = cCategory;
209 info.syntax = "category <list of items, separated by ;>";
210 info.help = "Adds the string <string> to the category information of the black box being defined";
211 mCommandDict[info.category] = info;
213 info.category = "description";
216 info.code = cDescription;
217 info.syntax = "description <string>";
218 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
219 mCommandDict[info.category] = info;
221 info.category = "help";
225 info.syntax = "help";
226 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>";
227 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.";
228 mCommandDict[info.category] = info;
230 info.category = "message";
233 info.code = cMessage;
234 info.syntax = "message <kind> <level>";
235 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;
237 info.category = "include";
240 info.code = cInclude;
241 info.syntax = "include <filename> [source]";
242 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).";
243 mCommandDict[info.category] = info;
245 info.category = "quit";
249 info.syntax = "quit";
250 info.help = "Quits the program (during script execution it stops the complete execution)";
251 mCommandDict[info.category] = info;
253 info.category = "load";
257 info.syntax = "load <packagename>";
258 info.help = "Loads the black box package <packagename>";
259 mCommandDict[info.category] = info;
261 info.category = "unload";
265 info.syntax = "unload <packagename>";
266 info.help = "Unloads the black box package <packagename>";
267 mCommandDict[info.category] = info;
269 info.category = "graph";
273 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 ]]]]]]";
274 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')";
275 mCommandDict[info.category] = info;
278 info.category = "workspace";
281 info.code = cWorkspace;
282 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
283 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.";
284 mCommandDict[info.category] = info;
287 bbtkDebugDecTab("Interpreter",9);
290 //=======================================================================
294 //=======================================================================
298 Interpreter::~Interpreter()
300 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
303 bbtkDebugDecTab("Interpreter",9);
305 //=======================================================================
308 InterpreterError::InterpreterError( const std::string& message,
310 const std::string& script_file,
313 : Exception("Interpreter",0,message),
314 mInScriptFile(in_script_file),
315 mScriptFile(script_file),
316 mScriptLine(script_line)
319 InterpreterError::InterpreterError( const Exception& excep,
321 const std::string& script_file,
325 mInScriptFile(in_script_file),
326 mScriptFile(script_file),
327 mScriptLine(script_line)
330 //=======================================================================
331 void Interpreter::CatchBbtkException( const bbtk::Exception& e )
335 bool in_script = false;
336 std::string file("");
338 if (mFileName.size()) {
339 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
340 if (fs!=0) in_script = true;
341 file = mFileName.back();
345 throw InterpreterError(e,in_script,file,line);
349 std::stringstream mess;
350 mess << "* ERROR : "<<e.GetMessage()<<std::endl;
351 if (mFileName.size()) {
352 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
353 mess << "* LINE : "<<mLine.back()<<std::endl;
355 std::cerr << mess.str();
358 //=======================================================================
360 //=======================================================================
361 void Interpreter::CatchStdException( const std::exception& e )
365 bool in_script = false;
366 std::string file("");
368 if (mFileName.size()) {
369 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
370 if (fs!=0) in_script = true;
371 file = mFileName.back();
375 throw InterpreterError(e.what(),in_script,file,line);
379 std::stringstream mess;
380 mess << "* ERROR : "<<e.what()<<std::endl;
381 if (mFileName.size()) {
382 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
383 mess << "* LINE : "<<mLine.back()<<std::endl;
385 std::cerr << mess.str();
388 //=======================================================================
390 //=======================================================================
391 void Interpreter::CatchUnknownException()
395 bool in_script = false;
396 std::string file("");
398 if (mFileName.size()) {
399 std::ifstream* fs = dynamic_cast<std::ifstream*>(mFile.back());
400 if (fs!=0) in_script = true;
401 file = mFileName.back();
405 throw InterpreterError("Unknown exception caught",
406 in_script,file,line);
410 std::stringstream mess;
411 mess << "* UNDEFINED ERROR (not a bbtk nor a std exception)"
413 if (mFileName.size()) {
414 mess << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
415 mess << "* LINE : "<<mLine.back()<<std::endl;
417 std::cerr << mess.str();
420 //=======================================================================
422 //=======================================================================
424 #define CATCH_MACRO \
425 catch (QuitException e) \
427 status = Interpreter_QUIT; \
428 if (mThrow) throw QuitException(); \
430 catch (bbtk::Exception e) \
432 status = Interpreter_ERROR; \
433 CatchBbtkException(e); \
435 catch (std::exception& e) \
437 status = Interpreter_ERROR; \
438 CatchStdException(e); \
442 status = Interpreter_ERROR; \
443 CatchUnknownException(); \
445 //=======================================================================
448 //=======================================================================
452 Interpreter::ExitStatus Interpreter::InterpretFile( const std::string& filename )
454 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
456 bool exm = mCommandLine;
457 mCommandLine = false;
459 ExitStatus status = Interpreter_OK;
463 SwitchToFile(filename);
465 bool insideComment = false; // for multiline comment
466 while (mFile.size()>0)
468 while (!mFile.back()->eof()) {
471 mFile.back()->getline(buf,500);
472 std::string str(buf);
473 int size=str.length();
474 if ( str[ size-1 ]==13 )
479 InterpretLine(str, insideComment);
488 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
489 bbtkDecTab("Interpreter",9);
495 //=======================================================================
498 //=======================================================================
502 Interpreter::ExitStatus
503 Interpreter::InterpretBuffer( std::stringstream* buffer )
505 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
507 bool exm = mCommandLine;
508 mCommandLine = false;
510 ExitStatus status = Interpreter_OK;
514 SwitchToStream(buffer);
515 bool insideComment = false; // for multiline comment
516 while (mFile.size()>0)
518 while (!mFile.back()->eof()) {
521 mFile.back()->getline(buf,500);
522 std::string str(buf);
524 int size=str.length();
525 if ( str[ size-1 ]==13 )
530 InterpretLine(str, insideComment);
540 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
541 bbtkDecTab("Interpreter",9);
546 //=======================================================================
548 //=======================================================================
549 /// Runs the interpretation of a command
550 Interpreter::ExitStatus Interpreter::InterpretLine( const std::string& line )
552 printf("EED Interpreter::InterpretLine %s \n", line.c_str() );
553 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine('"<<line<<"')"<<std::endl);
555 ExitStatus status = Interpreter_OK;
559 bool insideComment = false;
560 InterpretLine(line, insideComment);
564 catch (QuitException e)
566 status = Interpreter_QUIT;
568 catch (bbtk::Exception e)
570 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
571 status = Interpreter_ERROR;
573 catch (std::exception& e)
575 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
576 status = Interpreter_ERROR;
581 << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
582 status = Interpreter_ERROR;
586 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretLine()"
588 bbtkDecTab("Interpreter",9);
594 //=======================================================================
598 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
600 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
601 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
603 std::vector<std::string> words;
604 SplitLine(line,words);
609 bbtkDebugDecTab("Interpreter",9);
613 // Single line comment : # or //
614 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
616 bbtkDebugDecTab("Interpreter",9);
617 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
621 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
623 if (words[0][0]=='/' && words[0][1]=='*')
625 bbtkDebugDecTab("Interpreter",9);
626 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
627 insideComment = true;
631 if (words[0][0]=='*' && words[0][1]=='/')
633 bbtkDebugDecTab("Interpreter",9);
634 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
635 if ( !insideComment ) {
636 bbtkDebugDecTab("Interpreter",9);
637 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
639 insideComment = false;
645 bbtkDebugDecTab("Interpreter",9);
646 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
651 CommandInfoType command;
652 InterpretCommand(words,command);
654 bbtkDebugMessage("Interpreter",9,
655 "Command='"<<command.category
656 <<"' code="<<command.code<<std::endl);
658 std::string left,right,left2,right2;
659 std::string filename;
660 switch (command.code)
663 mExecuter->Create(words[1],words[2]);
667 mExecuter->Destroy(words[1]);
671 Utilities::SplitAroundFirstDot(words[1],left,right);
672 Utilities::SplitAroundFirstDot(words[2],left2,right2);
673 mExecuter->Connect(left,right,left2,right2);
677 mExecuter->BeginPackage(words[1]);
681 mExecuter->EndPackage();
685 if (mFileName.size()>0)
687 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
691 mExecuter->Define(words[1],"",filename);
695 mExecuter->Define(words[1],words[2],filename);
700 mExecuter->EndDefine();
704 mExecuter->Print(words[1]);
708 if (words[1]=="freeze")
709 mExecuter->SetNoExecMode(true);
710 else if (words[1]=="unfreeze")
711 mExecuter->SetNoExecMode(false);
713 mExecuter->Execute(words[1]);
717 Utilities::SplitAroundFirstDot(words[2],left,right);
718 mExecuter->DefineInput(words[1],left,right,words[3]);
722 Utilities::SplitAroundFirstDot(words[2],left,right);
723 mExecuter->DefineOutput(words[1],left,right,words[3]);
727 Utilities::SplitAroundFirstDot(words[1],left,right);
728 mExecuter->Set(left,right,words[2]);
732 mExecuter->Author(words[1]);
736 mExecuter->Category(words[1]);
741 Index("tmp_index.html");
742 else if (words.size()==2)
744 else if (words.size()==3)
745 Index(words[1],words[2]);
749 mExecuter->Description(words[1]);
759 mExecuter->HelpMessages();
763 sscanf(words[2].c_str(),"%d",&level);
764 mExecuter->SetMessageLevel(words[1],level);
777 this->mExecuter->Reset();
783 InterpretFile(words[1]);
787 SwitchToFile(words[1]);
789 // if 'source' was given
792 GetExecuter()->SetCurrentFileName(words[1]);
797 GetExecuter()->LoadPackage(words[1]);
801 GetExecuter()->UnLoadPackage(words[1]);
806 throw QuitException();
810 if (words.size() == 2)
812 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
813 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
817 mExecuter->SetWorkspaceName(words[2]);
822 bbtkInternalError("should not reach here !!!");
825 bbtkDecTab("Interpreter",9);
827 //=======================================================================
833 //=======================================================================
837 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
839 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
841 std::string delimiters = "\"";
842 std::vector<std::string> quote;
843 Utilities::SplitString(str,delimiters,quote);
846 std::vector<std::string>::iterator i;
847 for (i=quote.begin(); i!=quote.end(); )
849 Utilities::SplitString(*i,delimiters,tokens);
853 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
854 tokens.push_back(*i);
859 for (i=tokens.begin(); i!=tokens.end(); ++i)
861 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
863 bbtkDebugMessageCont("Interpreter",9,std::endl);
865 bbtkDebugDecTab("Interpreter",9);
867 //=======================================================================
872 //=======================================================================
877 void Interpreter::Print( const std::string& str)
879 if (mExecuter->GetNoExecMode()) return;
881 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
884 // InterpretLine ("load std")
885 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
886 // InterpretLine("new Print _P_")
887 // InterpretLine("connect _C_.Out _P_.In")
891 std::vector<std::string> chains;
892 std::string delimiters("$");
894 // Skip delimiters at beginning.
895 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
897 if (lastPos>0) is_text = false;
899 // Find first delimiter.
900 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
902 while (std::string::npos != pos || std::string::npos != lastPos)
906 // Found a text token, add it to the vector.
907 chains.push_back(str.substr(lastPos, pos - lastPos));
908 // std::string token = str.substr(lastPos, pos - lastPos)
909 // InterpretLine("set _C_.In%num% %token%")
915 // is an output (between $$) : decode
916 std::string tok,box,output;
917 tok = str.substr(lastPos, pos - lastPos);
918 Utilities::SplitAroundFirstDot(tok,box,output);
919 chains.push_back( mExecuter->Get(box,output) );
921 // InterpretLine("connect %tok% _C_.In%num%")
924 // Skip delimiters. Note the "not_of"
925 lastPos = str.find_first_not_of(delimiters, pos);
926 // Find next delimiter
927 pos = str.find_first_of(delimiters, lastPos);
932 // InterpretLine("exec _P_")
933 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
935 std::vector<std::string>::iterator i;
936 for (i= chains.begin(); i!=chains.end(); ++i)
938 // bbtkMessage("Echo",1,*i);
939 Utilities::SubsBackslashN(*i);
942 std::cout << std::endl;
943 bbtkDebugDecTab("Interpreter",9);
947 //=======================================================================
952 // ===================================================================================
954 void Interpreter::SwitchToFile( const std::string& name )
956 // Note : in the following :
957 // name : the user supplied name
958 // - abreviated name e.g. scr scr.bbs
959 // - relative full name e.g. ./scr.bbs ../../scr.bbs
960 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
961 // same for Windows, with c:, d: ...
963 // use ./directory/subdir/scrname.bbs
966 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
967 <<name<<"\")"<<std::endl);
969 std::vector<std::string> script_paths;
970 std::string fullPathScriptName; // full path script name
971 std::string pkgname; // e.g. <scriptname>.bbs
972 std::vector<std::string> Filenames;
974 // The following is *NOT* a debug time message :
975 // It's a user intended message.
976 // Please don't remove it.
977 bbtkMessage("Interpreter",1,
978 "look for : [" << name
979 << "]" << std::endl);
983 pkgname = Utilities::ExtractScriptName(name,upath);
985 bbtkMessage("Interpreter",3,
986 "extract : pkgname [" << pkgname
987 << "] upath [" << upath << "]" << std::endl);
988 bool fullnameGiven = false;
989 bool foundFile = false;
991 // ==== "*" provided : load all scripts in given path
992 // relative (e.g. std/boxes/*) or absolute
997 std::stringstream* stream = new std::stringstream;
998 //if (upath.size()!=0) // avoid troubles for "*"
1000 // ==== no path provided : look in root bbs path
1001 if (upath.size()==0)
1003 // bbtkMessage("Interpreter",1,
1004 script_paths.push_back( ConfigurationFile::GetInstance().Get_root_bbs_path() );
1006 // ==== absolute path provided
1007 else if (upath[0]=='/' || upath[1] == ':' )
1009 if ( Utilities::IsDirectory( upath ) )
1011 script_paths.push_back(upath);
1015 bbtkError("'"<<upath<<"' : directory does not exist");
1018 // ==== relative path provided : search all bbs path appended with
1019 // the relative path provided
1022 std::vector<std::string>::const_iterator i;
1023 for (i=ConfigurationFile::GetInstance().Get_bbs_paths().begin();
1024 i!=ConfigurationFile::GetInstance().Get_bbs_paths().end();
1027 std::string full_path(*i);
1028 // we *really* want '.' to be the current working directory
1029 if (full_path == ".") {
1030 char buf[2048]; // for getcwd
1031 char * currentDir = getcwd(buf, 2048);
1032 std::string cwd(currentDir);
1033 full_path = currentDir;
1036 full_path += ConfigurationFile::GetInstance().Get_file_separator();
1039 if ( Utilities::IsDirectory( full_path ) )
1041 script_paths.push_back(full_path);
1044 if (script_paths.empty())
1046 bbtkError("no '"<<upath<<"' subdir found in search paths"
1051 // === search paths list complete : now explore it
1054 std::vector<std::string>::iterator i;
1055 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
1057 bbtkMessage("Interpreter",1,
1058 "--> Looking in '" << *i << "'" << std::endl);
1062 int nbFiles = Utilities::Explore(*i, false, Filenames);
1065 for (std::vector<std::string>::iterator j = Filenames.begin();
1066 j!= Filenames.end(); ++j)
1068 int lgr = (*j).size();
1070 continue; // ignore non .bbs file
1071 if ((*j).substr(lgr-4, 4) != ".bbs")
1074 (*stream) << "include \"" << *j << "\"\n";
1075 bbtkMessage("Interpreter",2,
1076 " --> Found '" << *j << "'" << std::endl);
1083 bbtkMessage("Interpreter",1,
1084 " --> No .bbs found"<< std::endl);
1088 bbtkMessage("Interpreter",1,
1089 " --> "<<nbBssFiles<<" .bbs found"<< std::endl);
1090 SwitchToStream(stream);
1093 //break; // a directory was found; we stop iterating
1094 // LG : No! We want all files included !
1098 //=============== end pkgname=="*" ===========
1101 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1102 // (not only a plain script name)
1103 // we trust him, and try to expland the directory name
1104 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1106 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1109 // ===========================================================check user supplied location
1110 fullnameGiven = true;
1112 fullPathScriptName = Utilities::ExpandLibName(name, false);
1114 // allow user to always forget ".bbs"
1115 int l = fullPathScriptName.size();
1121 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1123 fullPathScriptName = fullPathScriptName + ".bbs";
1128 fullPathScriptName = fullPathScriptName + ".bbs";
1131 if ( Utilities::FileExists(fullPathScriptName))
1138 // =============================== iterate on the paths
1140 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
1142 std::vector<std::string>::iterator i;
1143 for (i=script_paths.begin();i!=script_paths.end();++i)
1146 // we *really* want '.' to be the current working directory
1148 char buf[2048]; // for getcwd
1149 char * currentDir = getcwd(buf, 2048);
1150 std::string cwd(currentDir);
1154 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1156 // Check if library exists
1157 if ( ! Utilities::FileExists(fullPathScriptName) )
1159 // The following is *NOT* a debug time message :
1160 // It's a user intended message.
1161 // Please don't remove it.
1162 bbtkMessage("Interpreter",2,
1163 " [" <<fullPathScriptName <<"] : doesn't exist"
1165 continue; // try next path
1167 bbtkMessage("Interpreter",2,
1168 " [" <<fullPathScriptName
1169 <<"] : found" <<std::endl);
1171 break; // a script was found; we stop iterating
1173 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1179 if(fullPathScriptName == "")
1180 bbtkError("Path ["<<upath<<"] doesn't exist");
1182 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1184 bbtkError("No ["<<pkgname<<".bbs] script found");
1188 LoadScript(fullPathScriptName,name);
1192 //=======================================================================
1195 //=======================================================================
1196 void Interpreter::SwitchToStream( std::stringstream* stream )
1198 mFile.push_back(stream);
1199 std::ostringstream buffer_name;
1201 buffer_name << "buffer_" ;
1203 if (mFileName.size()>0 )
1205 buffer_name << mFileName.back() << "_" << mLine.back();
1207 mFileName.push_back(buffer_name.str());
1208 mIncludeFileName.push_back(buffer_name.str());
1211 //=======================================================================
1213 //=======================================================================
1215 void Interpreter::LoadScript( std::string fullPathScriptName,
1216 std::string includeScriptName)
1218 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1220 bool okScriptExist=false;
1221 int iStrScript,sizeVecStricpt=mFileName.size();
1222 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1224 if (mFileName[iStrScript] == fullPathScriptName )
1230 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1231 // if (okScriptExist==true)
1233 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1234 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1239 s = new std::ifstream;
1240 s->open(fullPathScriptName.c_str());
1243 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1247 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1248 << "] found" << std::endl);
1251 mFileName.push_back(fullPathScriptName);
1252 mIncludeFileName.push_back(includeScriptName);
1258 //=======================================================================
1262 void Interpreter::CloseCurrentFile()
1264 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1267 if (mFile.size()==0)
1269 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1273 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1275 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1276 if (file!=0) file->close();
1278 delete mFile.back();
1280 mFileName.pop_back();
1281 mIncludeFileName.pop_back();
1284 bbtkDebugMessage("Interpreter",9," Remains "
1286 <<" open"<<std::endl);
1287 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1290 //=======================================================================
1292 //=======================================================================
1296 void Interpreter::CloseAllFiles()
1298 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1301 while (mFile.size() != 0)
1305 mFile.back()->close();
1306 delete mFile.back();
1308 bbtkDebugMessage("Interpreter",9,
1309 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1310 mFileName.pop_back();
1311 mIncludeFileName.pop_back();
1315 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1318 //=======================================================================
1322 //=======================================================================
1326 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1327 CommandInfoType& info )
1329 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1331 // searches the command category
1332 CommandDictType::iterator c;
1333 c = mCommandDict.find(words[0]);
1334 if ( c == mCommandDict.end() ) {
1335 bbtkError(words[0]<<" : unknown command");
1338 // tests the number of args
1339 if ( ( words.size()-1 < c->second.argmin ) ||
1340 ( words.size()-1 > c->second.argmax ) )
1342 HelpCommand(words[0]);
1343 bbtkError(words[0]<<" : wrong number of arguments");
1347 bbtkDecTab("Interpreter",9);
1349 //=======================================================================
1352 //=======================================================================
1353 /// Displays help on all the commands
1354 void Interpreter::Help(const std::vector<std::string>& words)
1356 unsigned int nbarg = words.size()-1;
1364 if (words[1]=="packages")
1366 GetExecuter()->GetFactory()->PrintPackages(true);
1371 HelpCommand(words[1]);
1373 catch (bbtk::Exception e)
1377 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1381 ConfigurationFile::GetInstance().Get_doc_path();
1382 url += "/bbdoc/" + words[1] + "/index.html";
1383 if (Utilities::FileExists(url))
1385 mUser->InterpreterUserViewHtmlPage(url);
1389 catch (bbtk::Exception f)
1393 std::string package;
1394 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1398 ConfigurationFile::GetInstance().Get_doc_path();
1399 url += "/bbdoc/" + package + "/index.html";
1400 if (Utilities::FileExists(url))
1402 url += "#" + words[1];
1403 mUser->InterpreterUserViewHtmlPage(url);
1407 catch (bbtk::Exception g)
1411 GetExecuter()->ShowRelations(words[1],"0","9999");
1413 catch (bbtk::Exception h){
1414 bbtkError("\""<<words[1].c_str()
1415 <<"\" is not a known command, package, black box type or black box name");
1423 if (words[2]=="all")
1425 if ( words[1]=="packages" )
1427 GetExecuter()->GetFactory()->PrintPackages(true,true);
1432 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1434 catch (bbtk::Exception f)
1440 HelpCommand(words[0]);
1441 bbtkError(words[0]<<" : syntax error");
1446 bbtkError("Should not reach here !!!");
1449 //=======================================================================
1451 //===================================================================
1452 /// Displays the Configuration
1453 void Interpreter::Config() const
1455 ConfigurationFile::GetInstance().GetHelp(1);
1457 //===================================================================
1459 //=======================================================================
1460 /// Displays help on all the commands
1461 void Interpreter::HelpCommands()
1463 std::cout << "Available commands :" << std::endl;
1464 CommandDictType::iterator i;
1465 for ( i = mCommandDict.begin();
1466 i != mCommandDict.end();
1468 std::cout << " " << i->first << std::endl;
1469 // std::cout << " usage : " << i->second.syntax << std::endl;
1470 // std::cout << " " << i->second.help << std::endl;
1474 //=======================================================================
1477 //=======================================================================
1478 /// Displays help on a particular commands
1479 void Interpreter::HelpCommand(const std::string& s)
1481 CommandDictType::iterator c;
1482 c = mCommandDict.find(s);
1483 if ( c == mCommandDict.end() ) {
1484 bbtkError(s<<" : Unknown command");
1486 // std::cout << " " << s << " : "<< std::endl;
1487 // CommandParamDictType::iterator i;
1488 // for ( i = c->second.begin();
1489 // i != c->second.end();
1491 std::cout << " usage : " << c->second.syntax << std::endl;
1492 std::cout << " " << c->second.help << std::endl;
1495 //=======================================================================
1498 //=======================================================================
1499 /// Fills the vector commands with the commands which
1500 /// have the first n chars of buf for prefix
1501 /// TODO : skip initial spaces in buf and also return the position of first
1502 /// non blank char in buf
1503 void Interpreter::FindCommandsWithPrefix( char* buf,
1505 std::vector<std::string>& commands )
1507 CommandDictType::const_iterator i;
1508 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1510 if ((i->first).find(buf,0,n) == 0)
1511 commands.push_back(i->first);
1514 //=======================================================================
1518 //=======================================================================
1519 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1521 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1522 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1524 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1525 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1526 // E.G. STORE THIS IN bbtk_config.xml
1527 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1528 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1529 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1530 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1531 #define BBTK_BACKSPACE_KBCODE 0x00000008
1532 #define BBTK_DEL_KBCODE 0x0000007F
1533 #define BBTK_SPACE_KBCODE 0x00000020
1535 //=======================================================================
1536 void Interpreter::GetLineFromPrompt(std::string& s)
1541 int MAX_LINE_SIZE = 160;
1542 int MAX_HISTORY_SIZE = 100;
1544 char* newline = new char[MAX_LINE_SIZE];
1545 memset(newline,0,MAX_LINE_SIZE);
1546 char* histline = new char[MAX_LINE_SIZE];
1547 memset(histline,0,MAX_LINE_SIZE);
1549 char* line = newline;
1550 int hist = mHistory.size();
1556 read ( STDIN_FILENO, &c, 4) ;
1558 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1560 // Printable character
1561 if ( (ind<MAX_LINE_SIZE-1) &&
1562 ( c >= BBTK_SPACE_KBCODE ) &&
1563 ( c < BBTK_DEL_KBCODE ))
1571 // delete the unused line
1577 // empty lines are not stored in from history
1580 // if history too long : delete oldest command
1581 if (mHistory.size()>MAX_HISTORY_SIZE)
1583 delete mHistory.front();
1584 mHistory.pop_front();
1586 mHistory.push_back(line);
1591 else if ( (ind>0) &&
1592 ((c == BBTK_BACKSPACE_KBCODE) ||
1593 (c == BBTK_DEL_KBCODE)) )
1601 // TODO : Command completion
1602 std::vector<std::string> commands;
1603 FindCommandsWithPrefix( line,ind,commands);
1604 if (commands.size()==1)
1606 std::string com = *commands.begin();
1607 for (; ind<com.size(); ++ind)
1609 PrintChar(com[ind]);
1615 else if (commands.size()>1)
1617 std::vector<std::string>::iterator i;
1619 for (i=commands.begin();i!=commands.end();++i)
1621 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1624 write(STDOUT_FILENO,"\n> ",3);
1625 //for (int j=0;j<ind;++j)
1627 write(STDOUT_FILENO,line,ind);
1631 // Arrow up : back in history
1632 else if (c==BBTK_UP_ARROW_KBCODE)
1636 // erase current line
1637 while (ind--) BackSpace();
1641 strcpy(histline,mHistory[hist]);
1645 write(STDOUT_FILENO,line,ind);
1648 // Arrow down : down in history
1649 else if (c==BBTK_DOWN_ARROW_KBCODE)
1651 if (hist<mHistory.size()-1)
1653 // erase current line
1654 while (ind--) BackSpace();
1658 strcpy(histline,mHistory[hist]);
1662 write(STDOUT_FILENO,line,ind);
1664 // end of history : switch back to newline
1665 else if (hist==mHistory.size()-1)
1667 // erase current line
1668 while (ind--) BackSpace();
1675 write(STDOUT_FILENO,line,ind);
1679 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1681 PrintChar(line[ind]);
1686 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1694 write(STDOUT_FILENO,"\n\r",2);
1702 //=======================================================================
1703 void Interpreter::GetLineFromPrompt(std::string& s)
1729 //=======================================================================
1735 //=======================================================================
1736 void Interpreter::CommandLineInterpreter()
1738 bbtkDebugMessageInc("Interpreter",9,
1739 "Interpreter::CommandLineInterpreter()"<<std::endl);
1741 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1742 // Initialise the tty in non canonical mode with no echo
1743 // oter remembers the previous settings to restore them after
1744 struct termios ter,oter;
1747 ter.c_lflag &= ~ECHO;
1748 ter.c_lflag &= ~ICANON;
1751 tcsetattr(0,TCSANOW,&ter);
1754 mCommandLine = true;
1756 bool insideComment = false; // for multiline comment
1762 GetLineFromPrompt(line);
1763 InterpretLine(line, insideComment);
1765 catch (QuitException e)
1767 bbtkMessage("Interpreter",1,"Interpreter : Quit"<<std::endl);
1770 catch (bbtk::Exception e)
1774 catch (std::exception& e)
1776 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1780 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1785 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1786 tcsetattr(0,TCSANOW,&oter);
1789 std::cout << "Good bye !" << std::endl;
1791 bbtkDebugDecTab("Interpreter",9);
1794 //=======================================================================
1795 void Interpreter::Graph(const std::vector<std::string>& words)
1798 bool system_display = true;
1800 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1801 system_display = false;
1803 if (words.size()==1)
1805 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1807 else if (words.size()==2)
1809 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1811 else if (words.size()==3)
1813 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1815 else if (words.size()==4)
1817 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1819 else if (words.size()==5)
1821 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1823 else if (words.size()==6)
1825 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1827 else if (words.size()==7)
1829 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1832 if ( ( mUser != 0 ) && ( mUser->InterpreterUserHasOwnHtmlPageViewer() ) )
1833 mUser->InterpreterUserViewHtmlPage(page);
1836 //=======================================================================
1839 //=======================================================================
1840 void Interpreter::Index(const std::string& filename,
1841 const std::string& type)
1843 Factory::IndexEntryType t;
1844 if (type=="Initials") t = Factory::Initials;
1845 else if (type=="Categories") t = Factory::Categories;
1846 else if (type=="Packages") t = Factory::Packages;
1847 else if (type=="Adaptors") t = Factory::Adaptors;
1849 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1851 //=======================================================================