1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/14 14:58:53 $
7 Version: $Revision: 1.44 $
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 "bbtkWxConsole.h"
27 #include "bbtkUtilities.h"
30 #ifdef CMAKE_HAVE_TERMIOS_H
32 #define BBTK_USE_TERMIOS_BASED_PROMPT
40 //Interpreter* Interpreter::mGlobalInterpreter = NULL;
42 //=======================================================================
46 Interpreter::Interpreter()
48 #ifdef _USE_WXWIDGETS_
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 mExecuter = new bbtk::Executer();
59 mExecuter->SetInterpreter(this);
61 // For the time being, comment out previous line, and
62 // uncomment next line to check Transcriptor
64 //mExecuter = new bbtk::Transcriptor("GeneratedProgram.txt");
66 // Builds the commands dict
69 info.category = "new";
73 info.syntax = "new <type> <name>";
74 info.help = "Creates a new black box of type <type> with name <name>";
75 mCommandDict[info.category] = info;
77 info.category = "delete";
81 info.syntax = "delete <box>";
82 info.help = "Deletes the black box of name <box>";
83 mCommandDict[info.category] = info;
85 info.category = "connect";
89 info.syntax = "connect <box1.output> <box2.input>";
90 info.help = "Connects the ouput <output> of black box <box1> to the input <input> of black box <box2>";
91 mCommandDict[info.category] = info;
93 info.category = "print";
97 info.syntax = "print <string>";
98 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').";
99 mCommandDict[info.category] = info;
101 info.category = "exec";
105 info.syntax = "exec <box | 'freeze' | 'unfreeze' >";
106 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.";
107 mCommandDict[info.category] = info;
109 info.category = "package";
112 info.code = cPackage;
113 info.syntax = "package <name>";
114 info.help = "Begins the definition of a package.";
115 mCommandDict[info.category] = info;
117 info.category = "endpackage";
120 info.code = cEndPackage;
121 info.syntax = "endpackage";
122 info.help = "Ends the definition of a package.";
123 mCommandDict[info.category] = info;
125 info.category = "define";
129 info.syntax = "define <type> [<package>]";
130 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.";
131 mCommandDict[info.category] = info;
133 info.category = "endefine";
136 info.code = cEndDefine;
137 info.syntax = "endefine";
138 info.help = "Ends the definition of a new type of complex black box";
139 mCommandDict[info.category] = info;
141 info.category = "input";
145 info.syntax = "input <name> <box.input> <help>";
146 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";
147 mCommandDict[info.category] = info;
149 info.category = "output";
153 info.syntax = "output <name> <box.output> <help>";
154 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";
155 mCommandDict[info.category] = info;
157 info.category = "set";
161 info.syntax = "set <box.input> <value>";
162 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";
163 mCommandDict[info.category] = info;
165 info.category = "config"; // JPR
169 info.syntax = "config";
170 info.help = "Prints the value of all configuration parameters";
171 mCommandDict[info.category] = info;
173 info.category = "index"; // LG
178 info.syntax = "index [<filename> ['Initials'(default)|'Packages'|'Categories'|'Adaptors']]";
179 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.";
180 mCommandDict[info.category] = info;
182 info.category = "reset"; //EED
186 info.syntax = "reset";
187 info.help = "Deletes all boxes and unloads all packages (bbi is reset to its start state)";
188 mCommandDict[info.category] = info;
190 info.category = "author";
194 info.syntax = "author <string>";
195 info.help = "Adds the string <string> to the author information of the black box being defined";
196 mCommandDict[info.category] = info;
198 info.category = "category"; //JP
201 info.code = cCategory;
202 info.syntax = "category <list of items, separated by ;>";
203 info.help = "Adds the string <string> to the category information of the black box being defined";
204 mCommandDict[info.category] = info;
206 info.category = "description";
209 info.code = cDescription;
210 info.syntax = "description <string>";
211 info.help = "Adds the string <string> to the descriptive information of the black box being defined";
212 mCommandDict[info.category] = info;
214 info.category = "help";
218 info.syntax = "help";
219 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>";
220 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.";
221 mCommandDict[info.category] = info;
223 info.category = "message";
226 info.code = cMessage;
227 info.syntax = "message <kind> <level>";
228 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;
230 info.category = "include";
233 info.code = cInclude;
234 info.syntax = "include <filename> [source]";
235 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).";
236 mCommandDict[info.category] = info;
238 info.category = "quit";
242 info.syntax = "quit";
243 info.help = "Quits the program (during script execution it stops the complete execution)";
244 mCommandDict[info.category] = info;
246 info.category = "load";
250 info.syntax = "load <packagename>";
251 info.help = "Loads the black box package <packagename>";
252 mCommandDict[info.category] = info;
254 info.category = "unload";
258 info.syntax = "unload <packagename>";
259 info.help = "Unloads the black box package <packagename>";
260 mCommandDict[info.category] = info;
262 info.category = "graph";
266 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 ]]]]]]";
267 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')";
268 mCommandDict[info.category] = info;
271 info.category = "workspace";
274 info.code = cWorkspace;
275 info.syntax = "workspace < ( freeze | unfreeze ) | ( rename <newname> ) >";
276 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.";
277 mCommandDict[info.category] = info;
280 bbtkDebugDecTab("Interpreter",9);
283 //=======================================================================
287 //=======================================================================
291 Interpreter::~Interpreter()
294 std::cout << "=========================================~Interpreter()" << std::endl;
295 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
298 bbtkDebugDecTab("Interpreter",9);
300 //=======================================================================
303 //=======================================================================
307 void Interpreter::InterpretFile( const std::string& filename )
309 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
310 // std::cout << "==========================================Entree InterpretFile ["<<filename<<"] try SwitchToFile "<<std::endl;
311 bool exm = mCommandLine;
312 mCommandLine = false;
316 SwitchToFile(filename);
319 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
321 std::cout << "A=== [" << (*it) << "]" << std::endl;
324 bool insideComment = false; // for multiline comment
325 while (mFile.size()>0)
328 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
330 std::cout << "B=== [" << (*it) << "]" << std::endl;
333 //printf("EED --- %s --- Interpreter::InterpretFile \n", mFileName[0].c_str() );
334 //printf("EED --- %s --- Interpreter::InterpretFile \n", mFileName[0].c_str() );
336 //while ((mFile.size()>0) && !mFile.back()->eof() )
338 // std::cout << "mFile.size() "<< mFile.size() << " mFileName.back() [" << mFileName.back() << "]" << std::endl;
340 while (!mFile.back()->eof()) {
343 mFile.back()->getline(buf,500);
344 std::string str(buf);
345 // std::cout << " in InterpretFile mFile.back()->getline [" << str << "]" << std::endl;
346 int size=str.length();
347 if ( str[ size-1 ]==13 )
352 InterpretLine(str, insideComment);
354 //printf("EED Interpreter::InterpretFile %s\n", str.c_str() );
357 //if (mFile.size()>0)
361 catch (QuitException e)
364 catch (bbtk::Exception e)
366 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
367 if (mFileName.size()) {
368 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
369 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
372 catch (std::exception& e)
374 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
375 if (mFileName.size()) {
376 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
377 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
382 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
383 if (mFileName.size()) {
384 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
385 std::cout << "* LINE : "<<mLine.back()<<std::endl;
390 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
391 bbtkDecTab("Interpreter",9);
395 //=======================================================================
399 //=======================================================================
403 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
406 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
407 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
409 std::vector<std::string> words;
410 SplitLine(line,words);
415 bbtkDebugDecTab("Interpreter",9);
419 // Single line comment : # or //
420 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
422 bbtkDebugDecTab("Interpreter",9);
423 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
427 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
429 if (words[0][0]=='/' && words[0][1]=='*')
431 bbtkDebugDecTab("Interpreter",9);
432 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
433 insideComment = true;
437 if (words[0][0]=='*' && words[0][1]=='/')
439 bbtkDebugDecTab("Interpreter",9);
440 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
441 if ( !insideComment ) {
442 bbtkDebugDecTab("Interpreter",9);
443 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
445 insideComment = false;
451 bbtkDebugDecTab("Interpreter",9);
452 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
457 CommandInfoType command;
458 InterpretCommand(words,command);
460 bbtkDebugMessage("Interpreter",9,
461 "Command='"<<command.category
462 <<"' code="<<command.code<<std::endl);
464 std::string left,right,left2,right2;
465 std::string filename;
466 switch (command.code)
469 mExecuter->Create(words[1],words[2]);
474 // mExecuter->Remove(words[1]);
478 Utilities::SplitAroundFirstDot(words[1],left,right);
479 Utilities::SplitAroundFirstDot(words[2],left2,right2);
480 mExecuter->Connect(left,right,left2,right2);
484 mExecuter->BeginPackage(words[1]);
488 mExecuter->EndPackage();
492 if (mFileName.size()>0)
494 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
498 mExecuter->Define(words[1],"",filename);
502 mExecuter->Define(words[1],words[2],filename);
507 mExecuter->EndDefine();
511 Print(words[1]); /// \todo use generate command
515 if (words[1]=="freeze")
516 mExecuter->SetNoExecMode(true);
517 else if (words[1]=="unfreeze")
518 mExecuter->SetNoExecMode(false);
520 mExecuter->Update(words[1]);
524 Utilities::SplitAroundFirstDot(words[2],left,right);
525 mExecuter->DefineInput(words[1],left,right,words[3]);
529 Utilities::SplitAroundFirstDot(words[2],left,right);
530 mExecuter->DefineOutput(words[1],left,right,words[3]);
534 Utilities::SplitAroundFirstDot(words[1],left,right);
535 mExecuter->Set(left,right,words[2]);
539 mExecuter->Author(words[1]);
543 mExecuter->Category(words[1]);
548 Index("tmp_index.html");
549 else if (words.size()==2)
551 else if (words.size()==3)
552 Index(words[1],words[2]);
556 mExecuter->Description(words[1]);
566 bbtk::MessageManager::PrintInfo();
570 sscanf(words[2].c_str(),"%d",&level);
571 bbtk::MessageManager::SetMessageLevel(words[1],level);
584 this->mExecuter->Reset();
590 InterpretFile(words[1]);
594 SwitchToFile(words[1]);
596 // if 'source' was given
599 GetExecuter()->SetCurrentFileName(words[1]);
604 GetExecuter()->GetFactory()->LoadPackage(words[1]);
608 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
613 throw QuitException();
617 if (words.size() == 2)
619 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
620 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
624 mExecuter->SetWorkspaceName(words[2]);
629 bbtkInternalError("should not reach here !!!");
632 bbtkDecTab("Interpreter",9);
634 //=======================================================================
640 //=======================================================================
644 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
646 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
648 std::string delimiters = "\"";
649 std::vector<std::string> quote;
650 Utilities::SplitString(str,delimiters,quote);
653 std::vector<std::string>::iterator i;
654 for (i=quote.begin(); i!=quote.end(); )
656 Utilities::SplitString(*i,delimiters,tokens);
660 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
661 tokens.push_back(*i);
666 for (i=tokens.begin(); i!=tokens.end(); ++i)
668 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
670 bbtkDebugMessageCont("Interpreter",9,std::endl);
672 bbtkDebugDecTab("Interpreter",9);
674 //=======================================================================
677 //=======================================================================
678 // Replaces substrings "\\n" by a real carriage return "\n"
679 void SubsBackslashN ( std::string& s )
681 std::string ss("\\n");
682 std::string::size_type pos = 0;
685 while ( pos != std::string::npos )
687 s.replace(pos,2,cr,1);
688 pos = s.find(ss, pos-1);
691 //=======================================================================
694 //=======================================================================
698 void Interpreter::Print( const std::string& str)
700 if (mExecuter->GetNoExecMode()) return;
702 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
705 // InterpretLine ("load std")
706 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
707 // InterpretLine("new Print _P_")
708 // InterpretLine("connect _C_.Out _P_.In")
712 std::vector<std::string> chains;
713 std::string delimiters("$");
715 // Skip delimiters at beginning.
716 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
718 if (lastPos>0) is_text = false;
720 // Find first delimiter.
721 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
723 while (std::string::npos != pos || std::string::npos != lastPos)
727 // Found a text token, add it to the vector.
728 chains.push_back(str.substr(lastPos, pos - lastPos));
729 // std::string token = str.substr(lastPos, pos - lastPos)
730 // InterpretLine("set _C_.In%num% %token%")
736 // is an output (between $$) : decode
737 std::string tok,box,output;
738 tok = str.substr(lastPos, pos - lastPos);
739 Utilities::SplitAroundFirstDot(tok,box,output);
740 chains.push_back( mExecuter->Get(box,output) );
742 // InterpretLine("connect %tok% _C_.In%num%")
745 // Skip delimiters. Note the "not_of"
746 lastPos = str.find_first_not_of(delimiters, pos);
747 // Find next delimiter
748 pos = str.find_first_of(delimiters, lastPos);
753 // InterpretLine("exec _P_")
754 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
756 std::vector<std::string>::iterator i;
757 for (i= chains.begin(); i!=chains.end(); ++i)
759 // bbtkMessage("Echo",1,*i);
763 std::cout << std::endl;
764 bbtkDebugDecTab("Interpreter",9);
767 //=======================================================================
772 // ===================================================================================
774 void Interpreter::SwitchToFile( const std::string& name )
776 // Note : in the following :
777 // name : the user supplied name
778 // - abreviated name e.g. scr scr.bbs
779 // - relative full name e.g. ./scr.bbs ../../scr.bbs
780 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
781 // same for Windows, with c:, d: ...
783 // use ./directory/subdir/scrname.bbs
786 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
787 <<name<<"\")"<<std::endl);
789 std::vector<std::string> script_paths;
790 std::string fullPathScriptName; // full path script name
791 std::string pkgname; // e.g. <scriptname>.bbs
792 std::vector<std::string> Filenames;
794 // The following is *NOT* a debug time message :
795 // It's a user intended message.
796 // Please don't remove it.
797 bbtkMessage("Interpreter",1,
798 "look for : [" << name
799 << "]" << std::endl);
800 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
803 pkgname = Utilities::ExtractScriptName(name,upath);
805 bbtkMessage("Interpreter",1,
806 "extract : pkgname [" << pkgname
807 << "] upath [" << upath << "]" << std::endl);
808 bool fullnameGiven = false;
809 bool foundFile = false;
811 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
813 // std::cout << "JPR================== * found, load all boxes " << std::endl;
816 std::stringstream* stream = new std::stringstream;
817 //if (upath.size()!=0) // avoid troubles for "*"
819 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
821 // std::cout << "JPR================== absolute name, load all .bbs files " << std::endl;
822 int nbFiles = Utilities::Explore(upath, false, Filenames);
824 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
826 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
827 int lgr = (*i).size();
829 continue; // ignore non .bbs file
830 if ((*i).substr(lgr-4, 4) != ".bbs")
833 if (lgr > 10) // 10 -> '-appli.bbs'
835 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
836 continue; // ignore '-appli.bbs' files
839 (*stream) << "include " << *i << "\n";
843 bbtkMessage("Interpreter",2,
844 "WARNING : No '.bbs' file found in ["
845 << upath << "]" << std::endl);
847 SwitchToStream(stream);
852 std::vector<std::string>::iterator i;
853 std::string fullDirectoryName;
854 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
858 // we *really* want '.' to be the current working directory
860 char buf[2048]; // for getcwd
861 char * currentDir = getcwd(buf, 2048);
862 std::string cwd(currentDir);
866 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
869 // without last slash "\"
870 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
872 // Check if library exists
873 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
875 // The following is *NOT* a debug time message :
876 // It's a user intended message.
877 // Please don't remove it.
878 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
879 <<"] : doesn't exist" <<std::endl);
880 continue; // try next path
885 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
888 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
890 //EEDprintf("EED Interpreter::SwitchToFile %s\n",(*i).c_str() );
891 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
892 int lgr = (*i).size();
894 continue; // ignore non .bbs file
895 if ((*i).substr(lgr-4, 4) != ".bbs")
898 if (lgr > 10) // 10 -> '-appli.bbs'
900 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
901 continue; // ignore '-appli.bbs' files
904 (*stream) << "include " << *i << "\n";
908 bbtkMessage("Interpreter",1,
909 "WARNING : No '.bbs' file found in ["
910 << fullDirectoryName << "]" << std::endl);
912 SwitchToStream(stream);
914 //break; // a directory was found; we stop iterating
915 // LG : No! We want all files included !
920 //std::string::size_type slash_position = name.find_last_of("/\\");
922 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
923 // (not only a plain script name)
924 // we trust him, and try to expland the directory name
925 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
927 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
930 // ===========================================================check user supplied location
931 fullnameGiven = true;
933 fullPathScriptName = Utilities::ExpandLibName(name, false);
935 // allow user to always forget ".bbs"
936 int l = fullPathScriptName.size();
942 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
944 fullPathScriptName = fullPathScriptName + ".bbs";
949 fullPathScriptName = fullPathScriptName + ".bbs";
952 if ( Utilities::FileExists(fullPathScriptName))
959 // =============================================================== iterate on the paths
962 std::vector<std::string>::iterator i;
963 for (i=script_paths.begin();i!=script_paths.end();++i)
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 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
976 // Check if library exists
977 if ( ! Utilities::FileExists(fullPathScriptName) )
979 // The following is *NOT* a debug time message :
980 // It's a user intended message.
981 // Please don't remove it.
982 bbtkMessage("Interpreter",2,
983 " [" <<fullPathScriptName <<"] : doesn't exist"
985 continue; // try next path
987 bbtkMessage("Interpreter",2,
988 " [" <<fullPathScriptName
989 <<"] : found" <<std::endl);
991 break; // a script was found; we stop iterating
993 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
999 if(fullPathScriptName == "")
1000 bbtkError("Path ["<<upath<<"] doesn't exist");
1002 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1004 bbtkError("No ["<<pkgname<<".bbs] script found");
1008 LoadScript(fullPathScriptName,name);
1014 void Interpreter::SwitchToStream( std::stringstream* stream )
1016 //std::cout << "== 1 Entry in Interpreter::SwitchToStream " << std::endl;
1017 mFile.push_back(stream);
1018 //std::cout << " mFile.size() " << mFile.size() << std::endl;
1019 std::ostringstream buffer_name;
1021 buffer_name << "buffer_" ; // << bufferNb;
1023 // std::cout << " mFile.size() " << mFile.size() << std::endl;
1024 // std::cout << " mFileName.size() " << mFileName.size() << std::endl;
1025 // std::cout << " mLine.size() " << mLine.size() << std::endl;
1026 // std::vector<std::string>::iterator j = mFileName.begin();
1027 // std::cout << " mFileName.begin() succeeded" << std::endl;
1028 // std::cout << " mFileName[0] " << mFileName[0] << std::endl;
1029 //std::cout << " mFileName.begin() " << mFileName.begin() << std::endl;
1031 for( std::vector<std::string>::iterator i = mFileName.begin(); i!= mFileName.end(); ++i)
1034 std::cout << "Interpreter::SwitchToStream : mFileName [" << *i << "]" << std::endl;
1037 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1038 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1040 if (mFileName.size()>0 )// && (mFile.size()>0) ) // NO!!!
1042 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1043 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1044 buffer_name << mFileName.back() << "_" << mLine.back();
1046 //std::cout << "3 in Interpreter::SwitchToStream buffer_name :[" << buffer_name.str() << "]" << std::endl;
1047 mFileName.push_back(buffer_name.str());
1048 mIncludeFileName.push_back(buffer_name.str());
1052 //=======================================================================
1054 void Interpreter::LoadScript( std::string fullPathScriptName,
1055 std::string includeScriptName)
1057 //std::cout << "--------------------------EED Interpreter::LoadScript >>01\n" << std::endl;
1058 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1060 bool okScriptExist=false;
1061 int iStrScript,sizeVecStricpt=mFileName.size();
1062 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1064 //EED printf(" EED %d Interpreter::LoadScript %s __>>__ %s\n", iStrScript,mFileName[iStrScript].c_str(),fullPathScriptName.c_str() );
1066 if (mFileName[iStrScript] == fullPathScriptName )
1068 printf(" EED %d Interpreter::LoadScript iguales\n",iStrScript );
1073 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1074 // if (okScriptExist==true)
1076 //EED printf("EED Interpreter::LoadScript Exit method\n");
1077 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1078 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1083 s = new std::ifstream;
1084 s->open(fullPathScriptName.c_str());
1087 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1091 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1092 << "] found" << std::endl);
1095 mFileName.push_back(fullPathScriptName);
1096 mIncludeFileName.push_back(includeScriptName);
1098 //EED printf("EED Interpreter::LoadScript >>02\n");
1102 //=======================================================================
1106 void Interpreter::CloseCurrentFile()
1108 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1111 if (mFile.size()==0)
1113 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1117 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1119 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1120 if (file!=0) file->close();
1122 delete mFile.back();
1124 mFileName.pop_back();
1125 mIncludeFileName.pop_back();
1128 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName[0]<<"'"<<std::endl);
1131 mFile.erase( mFile.begin() );
1132 mFileName.erase( mFileName.begin() );
1133 mIncludeFileName.erase( mIncludeFileName.begin() );
1134 mLine.erase( mLine.begin() );
1137 bbtkDebugMessage("Interpreter",9," Remains "
1139 <<" open"<<std::endl);
1140 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1143 //=======================================================================
1145 //=======================================================================
1149 void Interpreter::CloseAllFiles()
1151 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1154 while (mFile.size() != 0)
1158 mFile.back()->close();
1159 delete mFile.back();
1161 bbtkDebugMessage("Interpreter",9,
1162 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1163 mFileName.pop_back();
1164 mIncludeFileName.pop_back();
1168 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1171 //=======================================================================
1175 //=======================================================================
1179 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1180 CommandInfoType& info )
1182 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1184 // searches the command category
1185 CommandDictType::iterator c;
1186 c = mCommandDict.find(words[0]);
1187 if ( c == mCommandDict.end() ) {
1188 bbtkError(words[0]<<" : unknown command");
1191 // tests the number of args
1192 if ( ( words.size()-1 < c->second.argmin ) ||
1193 ( words.size()-1 > c->second.argmax ) )
1195 HelpCommand(words[0]);
1196 bbtkError(words[0]<<" : wrong number of arguments");
1200 bbtkDecTab("Interpreter",9);
1202 //=======================================================================
1205 //=======================================================================
1206 /// Displays help on all the commands
1207 void Interpreter::Help(const std::vector<std::string>& words)
1209 unsigned int nbarg = words.size()-1;
1217 if (words[1]=="packages")
1219 GetExecuter()->GetFactory()->PrintPackages(true);
1224 HelpCommand(words[1]);
1226 catch (bbtk::Exception e)
1230 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1231 #ifdef _USE_WXWIDGETS_
1232 if ( mWxConsole != 0 )
1235 ConfigurationFile::GetInstance().Get_doc_path();
1236 url += "/bbdoc/" + words[1] + "/index.html";
1237 if (Utilities::FileExists(url))
1239 mWxConsole->ShowHtmlPage(url);
1244 catch (bbtk::Exception f)
1248 std::string package;
1249 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1250 #ifdef _USE_WXWIDGETS_
1251 if ( mWxConsole != 0 )
1254 ConfigurationFile::GetInstance().Get_doc_path();
1255 url += "/bbdoc/" + package + "/index.html";
1256 if (Utilities::FileExists(url))
1258 url += "#" + words[1];
1259 mWxConsole->ShowHtmlPage(url);
1264 catch (bbtk::Exception g)
1268 GetExecuter()->ShowRelations(words[1],"0","9999");
1270 catch (bbtk::Exception h){
1271 bbtkError("\""<<words[1].c_str()
1272 <<"\" is not a known command, package, black box type or black box name");
1280 if (words[2]=="all")
1282 if ( words[1]=="packages" )
1284 GetExecuter()->GetFactory()->PrintPackages(true,true);
1289 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1291 catch (bbtk::Exception f)
1297 HelpCommand(words[0]);
1298 bbtkError(words[0]<<" : syntax error");
1303 bbtkError("Should not reach here !!!");
1306 //=======================================================================
1308 //===================================================================
1309 /// Displays the Configuration
1310 void Interpreter::Config() const
1312 ConfigurationFile::GetInstance().GetHelp(1);
1314 //===================================================================
1316 //=======================================================================
1317 /// Displays help on all the commands
1318 void Interpreter::HelpCommands()
1320 std::cout << "Available commands :" << std::endl;
1321 CommandDictType::iterator i;
1322 for ( i = mCommandDict.begin();
1323 i != mCommandDict.end();
1325 std::cout << " " << i->first << std::endl;
1326 // std::cout << " usage : " << i->second.syntax << std::endl;
1327 // std::cout << " " << i->second.help << std::endl;
1331 //=======================================================================
1334 //=======================================================================
1335 /// Displays help on a particular commands
1336 void Interpreter::HelpCommand(const std::string& s)
1338 CommandDictType::iterator c;
1339 c = mCommandDict.find(s);
1340 if ( c == mCommandDict.end() ) {
1341 bbtkError(s<<" : Unknown command");
1343 // std::cout << " " << s << " : "<< std::endl;
1344 // CommandParamDictType::iterator i;
1345 // for ( i = c->second.begin();
1346 // i != c->second.end();
1348 std::cout << " usage : " << c->second.syntax << std::endl;
1349 std::cout << " " << c->second.help << std::endl;
1352 //=======================================================================
1355 //=======================================================================
1356 /// Fills the vector commands with the commands which
1357 /// have the first n chars of buf for prefix
1358 /// TODO : skip initial spaces in buf and also return the position of first
1359 /// non blank char in buf
1360 void Interpreter::FindCommandsWithPrefix( char* buf,
1362 std::vector<std::string>& commands )
1364 CommandDictType::const_iterator i;
1365 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1367 if ((i->first).find(buf,0,n) == 0)
1368 commands.push_back(i->first);
1371 //=======================================================================
1375 //=======================================================================
1376 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1378 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1379 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1381 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1382 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1383 // E.G. STORE THIS IN bbtk_config.xml
1384 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1385 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1386 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1387 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1388 #define BBTK_BACKSPACE_KBCODE 0x00000008
1389 #define BBTK_DEL_KBCODE 0x0000007F
1390 #define BBTK_SPACE_KBCODE 0x00000020
1392 //=======================================================================
1393 void Interpreter::GetLineFromPrompt(std::string& s)
1398 int MAX_LINE_SIZE = 160;
1399 int MAX_HISTORY_SIZE = 100;
1401 char* newline = new char[MAX_LINE_SIZE];
1402 memset(newline,0,MAX_LINE_SIZE);
1403 char* histline = new char[MAX_LINE_SIZE];
1404 memset(histline,0,MAX_LINE_SIZE);
1406 char* line = newline;
1407 int hist = mHistory.size();
1413 read ( STDIN_FILENO, &c, 4) ;
1415 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1417 // Printable character
1418 if ( (ind<MAX_LINE_SIZE-1) &&
1419 ( c >= BBTK_SPACE_KBCODE ) &&
1420 ( c < BBTK_DEL_KBCODE ))
1428 // delete the unused line
1434 // empty lines are not stored in from history
1437 // if history too long : delete oldest command
1438 if (mHistory.size()>MAX_HISTORY_SIZE)
1440 delete mHistory.front();
1441 mHistory.pop_front();
1443 mHistory.push_back(line);
1448 else if ( (ind>0) &&
1449 ((c == BBTK_BACKSPACE_KBCODE) ||
1450 (c == BBTK_DEL_KBCODE)) )
1458 // TODO : Command completion
1459 std::vector<std::string> commands;
1460 FindCommandsWithPrefix( line,ind,commands);
1461 if (commands.size()==1)
1463 std::string com = *commands.begin();
1464 for (; ind<com.size(); ++ind)
1466 PrintChar(com[ind]);
1472 else if (commands.size()>1)
1474 std::vector<std::string>::iterator i;
1476 for (i=commands.begin();i!=commands.end();++i)
1478 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1481 write(STDOUT_FILENO,"\n> ",3);
1482 //for (int j=0;j<ind;++j)
1484 write(STDOUT_FILENO,line,ind);
1488 // Arrow up : back in history
1489 else if (c==BBTK_UP_ARROW_KBCODE)
1493 // erase current line
1494 while (ind--) BackSpace();
1498 strcpy(histline,mHistory[hist]);
1502 write(STDOUT_FILENO,line,ind);
1505 // Arrow down : down in history
1506 else if (c==BBTK_DOWN_ARROW_KBCODE)
1508 if (hist<mHistory.size()-1)
1510 // erase current line
1511 while (ind--) BackSpace();
1515 strcpy(histline,mHistory[hist]);
1519 write(STDOUT_FILENO,line,ind);
1521 // end of history : switch back to newline
1522 else if (hist==mHistory.size()-1)
1524 // erase current line
1525 while (ind--) BackSpace();
1532 write(STDOUT_FILENO,line,ind);
1536 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1538 PrintChar(line[ind]);
1543 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1551 write(STDOUT_FILENO,"\n\r",2);
1559 //=======================================================================
1560 void Interpreter::GetLineFromPrompt(std::string& s)
1586 //=======================================================================
1592 //=======================================================================
1593 void Interpreter::CommandLineInterpreter()
1595 bbtkDebugMessageInc("Interpreter",9,
1596 "Interpreter::CommandLineInterpreter()"<<std::endl);
1598 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1599 // Initialise the tty in non canonical mode with no echo
1600 // oter remembers the previous settings to restore them after
1601 struct termios ter,oter;
1604 ter.c_lflag &= ~ECHO;
1605 ter.c_lflag &= ~ICANON;
1608 tcsetattr(0,TCSANOW,&ter);
1611 mCommandLine = true;
1613 bool insideComment = false; // for multiline comment
1619 GetLineFromPrompt(line);
1620 InterpretLine(line, insideComment);
1622 catch (QuitException e)
1626 catch (bbtk::Exception e)
1630 catch (std::exception& e)
1632 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1636 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1641 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1642 tcsetattr(0,TCSANOW,&oter);
1645 std::cout << "Good bye !" << std::endl;
1647 bbtkDebugDecTab("Interpreter",9);
1650 //=======================================================================
1651 void Interpreter::Graph(const std::vector<std::string>& words)
1654 bool system_display = true;
1656 #ifdef _USE_WXWIDGETS_
1657 if ( mWxConsole != 0 ) system_display = false;
1660 if (words.size()==1)
1662 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1664 else if (words.size()==2)
1666 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1668 else if (words.size()==3)
1670 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1672 else if (words.size()==4)
1674 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1676 else if (words.size()==5)
1678 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1680 else if (words.size()==6)
1682 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1684 else if (words.size()==7)
1686 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1689 #ifdef _USE_WXWIDGETS_
1690 if ( mWxConsole != 0 )
1691 mWxConsole->ShowHtmlPage(page);
1694 //=======================================================================
1697 //=======================================================================
1698 void Interpreter::Index(const std::string& filename,
1699 const std::string& type)
1701 Factory::IndexEntryType t;
1702 if (type=="Initials") t = Factory::Initials;
1703 else if (type=="Categories") t = Factory::Categories;
1704 else if (type=="Packages") t = Factory::Packages;
1705 else if (type=="Adaptors") t = Factory::Adaptors;
1707 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1709 //=======================================================================