1 /*=========================================================================
4 Module: $RCSfile: bbtkInterpreter.cxx,v $ $
6 Date: $Date: 2008/03/18 12:51:26 $
7 Version: $Revision: 1.46 $
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";
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()
293 bbtkDebugMessageInc("Interpreter",9,"Interpreter::~Interpreter()" <<std::endl);
296 bbtkDebugDecTab("Interpreter",9);
298 //=======================================================================
301 //=======================================================================
305 void Interpreter::InterpretFile( const std::string& filename )
307 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
308 // std::cout << "==========================================Entree InterpretFile ["<<filename<<"] try SwitchToFile "<<std::endl;
309 bool exm = mCommandLine;
310 mCommandLine = false;
314 SwitchToFile(filename);
317 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
319 std::cout << "A=== [" << (*it) << "]" << std::endl;
322 bool insideComment = false; // for multiline comment
323 while (mFile.size()>0)
326 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
328 std::cout << "B=== [" << (*it) << "]" << std::endl;
332 //while ((mFile.size()>0) && !mFile.back()->eof() )
334 // std::cout << "mFile.size() "<< mFile.size() << " mFileName.back() [" << mFileName.back() << "]" << std::endl;
335 while (!mFile.back()->eof()) {
338 mFile.back()->getline(buf,500);
339 std::string str(buf);
340 // std::cout << " in InterpretFile mFile.back()->getline [" << str << "]" << std::endl;
341 int size=str.length();
342 if ( str[ size-1 ]==13 )
347 InterpretLine(str, insideComment);
350 //if (mFile.size()>0)
354 catch (QuitException e)
357 catch (bbtk::Exception e)
359 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
360 if (mFileName.size()) {
361 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
362 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
365 catch (std::exception& e)
367 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
368 if (mFileName.size()) {
369 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
370 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
375 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
376 if (mFileName.size()) {
377 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
378 std::cout << "* LINE : "<<mLine.back()<<std::endl;
383 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretFile(\""<<filename<<"\")"<<std::endl);
384 bbtkDecTab("Interpreter",9);
388 //=======================================================================
391 //=======================================================================
395 void Interpreter::InterpretBuffer( std::stringstream* buffer )
397 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretBuffer()"<<std::endl);
398 // std::cout << "==========================================Entree InterpretFile ["<<filename<<"] try SwitchToFile "<<std::endl;
399 bool exm = mCommandLine;
400 mCommandLine = false;
404 SwitchToStream(buffer);
407 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
409 std::cout << "A=== [" << (*it) << "]" << std::endl;
412 bool insideComment = false; // for multiline comment
413 while (mFile.size()>0)
416 for( std::vector<std::string>::iterator it =mFileName.begin(); it!=mFileName.end(); ++it)
418 std::cout << "B=== [" << (*it) << "]" << std::endl;
422 //while ((mFile.size()>0) && !mFile.back()->eof() )
424 // std::cout << "mFile.size() "<< mFile.size() << " mFileName.back() [" << mFileName.back() << "]" << std::endl;
425 while (!mFile.back()->eof()) {
428 mFile.back()->getline(buf,500);
429 std::string str(buf);
430 // std::cout << " in InterpretFile mFile.back()->getline [" << str << "]" << std::endl;
431 int size=str.length();
432 if ( str[ size-1 ]==13 )
437 InterpretLine(str, insideComment);
440 //if (mFile.size()>0)
444 catch (QuitException e)
446 // std::cout << "**QuitException caught**"<<std::endl;
448 catch (bbtk::Exception e)
450 std::cerr << "* ERROR : "<<e.GetMessage()<<std::endl;
451 if (mFileName.size()) {
452 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
453 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
456 catch (std::exception& e)
458 std::cerr << "* ERROR : "<<e.what()<<" (not in bbtk)"<<std::endl;
459 if (mFileName.size()) {
460 std::cerr << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
461 std::cerr << "* LINE : "<<mLine.back()<<std::endl;
466 std::cout << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
467 if (mFileName.size()) {
468 std::cout << "* FILE : \""<<mFileName.back()<<"\""<<std::endl;
469 std::cout << "* LINE : "<<mLine.back()<<std::endl;
474 bbtkDebugMessage("Interpreter",9,"EO Interpreter::InterpretBuffer()"<<std::endl);
475 bbtkDecTab("Interpreter",9);
479 //=======================================================================
483 //=======================================================================
487 void Interpreter::InterpretLine( const std::string& line, bool &insideComment )
489 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretLine(\""<<line<<"\")"<<std::endl);
490 bbtkMessage("Echo",2,"\""<<line<<"\""<<std::endl);
492 std::vector<std::string> words;
493 SplitLine(line,words);
498 bbtkDebugDecTab("Interpreter",9);
502 // Single line comment : # or //
503 if ( words[0][0]=='#' || (words[0][0]=='/' && words[0][1]=='/') )
505 bbtkDebugDecTab("Interpreter",9);
506 bbtkMessage("Interpreter",9,"Comment"<<std::endl);
510 // Multi line comment ( /* ... */ ) -delimiters on different lines !-
512 if (words[0][0]=='/' && words[0][1]=='*')
514 bbtkDebugDecTab("Interpreter",9);
515 bbtkMessage("Interpreter",9,"In multiline comment"<<std::endl);
516 insideComment = true;
520 if (words[0][0]=='*' && words[0][1]=='/')
522 bbtkDebugDecTab("Interpreter",9);
523 bbtkMessage("Interpreter",9,"Out multiline comment"<<std::endl);
524 if ( !insideComment ) {
525 bbtkDebugDecTab("Interpreter",9);
526 bbtkMessage("Interpreter",9,"Comment mismatch : '*/' with no matching '/*'"<<std::endl);
528 insideComment = false;
534 bbtkDebugDecTab("Interpreter",9);
535 bbtkMessage("Interpreter",9,"Multiline Comment"<<std::endl);
540 CommandInfoType command;
541 InterpretCommand(words,command);
543 bbtkDebugMessage("Interpreter",9,
544 "Command='"<<command.category
545 <<"' code="<<command.code<<std::endl);
547 std::string left,right,left2,right2;
548 std::string filename;
549 switch (command.code)
552 mExecuter->Create(words[1],words[2]);
557 // mExecuter->Remove(words[1]);
561 Utilities::SplitAroundFirstDot(words[1],left,right);
562 Utilities::SplitAroundFirstDot(words[2],left2,right2);
563 mExecuter->Connect(left,right,left2,right2);
567 mExecuter->BeginPackage(words[1]);
571 mExecuter->EndPackage();
575 if (mFileName.size()>0)
577 filename = mIncludeFileName.back(); //Utilities::get_file_name(mFileName.back());
581 mExecuter->Define(words[1],"",filename);
585 mExecuter->Define(words[1],words[2],filename);
590 mExecuter->EndDefine();
594 Print(words[1]); /// \todo use generate command
598 if (words[1]=="freeze")
599 mExecuter->SetNoExecMode(true);
600 else if (words[1]=="unfreeze")
601 mExecuter->SetNoExecMode(false);
603 mExecuter->Update(words[1]);
607 Utilities::SplitAroundFirstDot(words[2],left,right);
608 mExecuter->DefineInput(words[1],left,right,words[3]);
612 Utilities::SplitAroundFirstDot(words[2],left,right);
613 mExecuter->DefineOutput(words[1],left,right,words[3]);
617 Utilities::SplitAroundFirstDot(words[1],left,right);
618 mExecuter->Set(left,right,words[2]);
622 mExecuter->Author(words[1]);
626 mExecuter->Category(words[1]);
631 Index("tmp_index.html");
632 else if (words.size()==2)
634 else if (words.size()==3)
635 Index(words[1],words[2]);
639 mExecuter->Description(words[1]);
649 bbtk::MessageManager::PrintInfo();
653 sscanf(words[2].c_str(),"%d",&level);
654 bbtk::MessageManager::SetMessageLevel(words[1],level);
667 this->mExecuter->Reset();
673 InterpretFile(words[1]);
677 SwitchToFile(words[1]);
679 // if 'source' was given
682 GetExecuter()->SetCurrentFileName(words[1]);
687 GetExecuter()->GetFactory()->LoadPackage(words[1]);
691 GetExecuter()->GetFactory()->UnLoadPackage(words[1]);
696 throw QuitException();
700 if (words.size() == 2)
702 if (words[1]=="freeze") mExecuter->SetNoExecMode(true);
703 else if (words[1]=="unfreeze") mExecuter->SetNoExecMode(false);
707 mExecuter->SetWorkspaceName(words[2]);
712 bbtkInternalError("should not reach here !!!");
715 bbtkDecTab("Interpreter",9);
717 //=======================================================================
723 //=======================================================================
727 void Interpreter::SplitLine ( const std::string& str, std::vector<std::string>& tokens)
729 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SplitLine(\""<<str<<"\")"<<std::endl);
731 std::string delimiters = "\"";
732 std::vector<std::string> quote;
733 Utilities::SplitString(str,delimiters,quote);
736 std::vector<std::string>::iterator i;
737 for (i=quote.begin(); i!=quote.end(); )
739 Utilities::SplitString(*i,delimiters,tokens);
743 // bbtkDebugMessage("Interpreter",0,"\""<<*i<<"\""<<std::endl);
744 tokens.push_back(*i);
749 for (i=tokens.begin(); i!=tokens.end(); ++i)
751 bbtkDebugMessage("Interpreter",9,"["<<*i<<"] ");
753 bbtkDebugMessageCont("Interpreter",9,std::endl);
755 bbtkDebugDecTab("Interpreter",9);
757 //=======================================================================
760 //=======================================================================
761 // Replaces substrings "\\n" by a real carriage return "\n"
762 void SubsBackslashN ( std::string& s )
764 std::string ss("\\n");
765 std::string::size_type pos = 0;
768 while ( pos != std::string::npos )
770 s.replace(pos,2,cr,1);
771 pos = s.find(ss, pos-1);
774 //=======================================================================
777 //=======================================================================
781 void Interpreter::Print( const std::string& str)
783 if (mExecuter->GetNoExecMode()) return;
785 bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
788 // InterpretLine ("load std")
789 // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande
790 // InterpretLine("new Print _P_")
791 // InterpretLine("connect _C_.Out _P_.In")
795 std::vector<std::string> chains;
796 std::string delimiters("$");
798 // Skip delimiters at beginning.
799 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
801 if (lastPos>0) is_text = false;
803 // Find first delimiter.
804 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
806 while (std::string::npos != pos || std::string::npos != lastPos)
810 // Found a text token, add it to the vector.
811 chains.push_back(str.substr(lastPos, pos - lastPos));
812 // std::string token = str.substr(lastPos, pos - lastPos)
813 // InterpretLine("set _C_.In%num% %token%")
819 // is an output (between $$) : decode
820 std::string tok,box,output;
821 tok = str.substr(lastPos, pos - lastPos);
822 Utilities::SplitAroundFirstDot(tok,box,output);
823 chains.push_back( mExecuter->Get(box,output) );
825 // InterpretLine("connect %tok% _C_.In%num%")
828 // Skip delimiters. Note the "not_of"
829 lastPos = str.find_first_not_of(delimiters, pos);
830 // Find next delimiter
831 pos = str.find_first_of(delimiters, lastPos);
836 // InterpretLine("exec _P_")
837 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
839 std::vector<std::string>::iterator i;
840 for (i= chains.begin(); i!=chains.end(); ++i)
842 // bbtkMessage("Echo",1,*i);
846 std::cout << std::endl;
847 bbtkDebugDecTab("Interpreter",9);
850 //=======================================================================
855 // ===================================================================================
857 void Interpreter::SwitchToFile( const std::string& name )
859 // Note : in the following :
860 // name : the user supplied name
861 // - abreviated name e.g. scr scr.bbs
862 // - relative full name e.g. ./scr.bbs ../../scr.bbs
863 // - absolute full name e.g. /home/usrname/proj/dir/scr.bbs
864 // same for Windows, with c:, d: ...
866 // use ./directory/subdir/scrname.bbs
869 bbtkDebugMessageInc("Interpreter",9,"Interpreter::SwitchToFile( \""
870 <<name<<"\")"<<std::endl);
872 std::vector<std::string> script_paths;
873 std::string fullPathScriptName; // full path script name
874 std::string pkgname; // e.g. <scriptname>.bbs
875 std::vector<std::string> Filenames;
877 // The following is *NOT* a debug time message :
878 // It's a user intended message.
879 // Please don't remove it.
880 bbtkMessage("Interpreter",1,
881 "look for : [" << name
882 << "]" << std::endl);
883 script_paths = ConfigurationFile::GetInstance().Get_bbs_paths();
886 pkgname = Utilities::ExtractScriptName(name,upath);
888 bbtkMessage("Interpreter",1,
889 "extract : pkgname [" << pkgname
890 << "] upath [" << upath << "]" << std::endl);
891 bool fullnameGiven = false;
892 bool foundFile = false;
894 if(pkgname == "*") // =========================================== load all boxes (e.g. std/boxes/*)
896 // std::cout << "JPR================== * found, load all boxes " << std::endl;
899 std::stringstream* stream = new std::stringstream;
900 //if (upath.size()!=0) // avoid troubles for "*"
902 if (upath[0]=='/' || upath[1] == ':' ) // ==== absolute name, load all .bbs files
904 // std::cout << "JPR================== absolute name, load all .bbs files " << std::endl;
905 int nbFiles = Utilities::Explore(upath, false, Filenames);
907 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
909 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
910 int lgr = (*i).size();
912 continue; // ignore non .bbs file
913 if ((*i).substr(lgr-4, 4) != ".bbs")
916 if (lgr > 10) // 10 -> '-appli.bbs'
918 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
919 continue; // ignore '-appli.bbs' files
923 (*stream) << "include " << *i << "\n";
924 //EED InterpretFile(*i);
929 bbtkMessage("Interpreter",2,
930 "WARNING : No '.bbs' file found in ["
931 << upath << "]" << std::endl);
933 SwitchToStream(stream);
939 std::vector<std::string>::iterator i;
940 std::string fullDirectoryName;
941 for (i=script_paths.begin();i!=script_paths.end();i++)// ==== relative name, iterate + load all .bbs files
945 // we *really* want '.' to be the current working directory
947 char buf[2048]; // for getcwd
948 char * currentDir = getcwd(buf, 2048);
949 std::string cwd(currentDir);
953 fullDirectoryName = Utilities::MakePkgnameFromPath(path, upath, false);
955 // without last slash "\"
956 std::string fullDirectoryNameClean = fullDirectoryName.substr(0,fullDirectoryName.size()-1);
958 // Check if library exists
959 if ( ! Utilities::IsDirectory( fullDirectoryNameClean ) )
961 // The following is *NOT* a debug time message :
962 // It's a user intended message.
963 // Please don't remove it.
964 bbtkMessage("Interpreter",1," [" <<fullDirectoryName
965 <<"] : doesn't exist" <<std::endl);
966 continue; // try next path
971 int nbFiles = Utilities::Explore(fullDirectoryName, false, Filenames);
974 for (std::vector<std::string>::iterator i = Filenames.begin(); i!= Filenames.end(); ++i)
976 // std::cout << "JPR================== iterate [" << *i << "]" << std::endl;
977 int lgr = (*i).size();
979 continue; // ignore non .bbs file
980 if ((*i).substr(lgr-4, 4) != ".bbs")
983 if (lgr > 10) // 10 -> '-appli.bbs'
985 if ((*i).substr(lgr-10, 10) == "-appli.bbs")
986 continue; // ignore '-appli.bbs' files
990 (*stream) << "include " << *i << "\n";
991 //EED InterpretFile(*i);
996 bbtkMessage("Interpreter",1,
997 "WARNING : No '.bbs' file found in ["
998 << fullDirectoryName << "]" << std::endl);
1000 SwitchToStream(stream);
1003 //break; // a directory was found; we stop iterating
1004 // LG : No! We want all files included !
1009 //std::string::size_type slash_position = name.find_last_of("/\\");
1011 // if name starts with a / or a . or contains : user is assumed to have passed a relative/absolute name
1012 // (not only a plain script name)
1013 // we trust him, and try to expland the directory name
1014 // WARNING : starting from current local directory : ./whatYouWant (./ mandatory!)
1016 if (name[0]=='/' || name[1] == ':' || name[0]=='.') // absolute path (linux/windows) or relative path
1019 // ===========================================================check user supplied location
1020 fullnameGiven = true;
1022 fullPathScriptName = Utilities::ExpandLibName(name, false);
1024 // allow user to always forget ".bbs"
1025 int l = fullPathScriptName.size();
1031 if (fullPathScriptName.substr(l-4, 4) != ".bbs")
1033 fullPathScriptName = fullPathScriptName + ".bbs";
1038 fullPathScriptName = fullPathScriptName + ".bbs";
1041 if ( Utilities::FileExists(fullPathScriptName))
1048 // =============================================================== iterate on the paths
1051 std::vector<std::string>::iterator i;
1052 for (i=script_paths.begin();i!=script_paths.end();++i)
1055 // we *really* want '.' to be the current working directory
1057 char buf[2048]; // for getcwd
1058 char * currentDir = getcwd(buf, 2048);
1059 std::string cwd(currentDir);
1063 fullPathScriptName = Utilities::MakePkgnameFromPath(path, name, true);
1065 // Check if library exists
1066 if ( ! Utilities::FileExists(fullPathScriptName) )
1068 // The following is *NOT* a debug time message :
1069 // It's a user intended message.
1070 // Please don't remove it.
1071 bbtkMessage("Interpreter",2,
1072 " [" <<fullPathScriptName <<"] : doesn't exist"
1074 continue; // try next path
1076 bbtkMessage("Interpreter",2,
1077 " [" <<fullPathScriptName
1078 <<"] : found" <<std::endl);
1080 break; // a script was found; we stop iterating
1082 } //------------------ // end for ( package_paths.begin();i!=package_paths.end() )
1088 if(fullPathScriptName == "")
1089 bbtkError("Path ["<<upath<<"] doesn't exist");
1091 bbtkError("Script ["<<fullPathScriptName<<"] not found");
1093 bbtkError("No ["<<pkgname<<".bbs] script found");
1097 LoadScript(fullPathScriptName,name);
1103 void Interpreter::SwitchToStream( std::stringstream* stream )
1105 //std::cout << "== 1 Entry in Interpreter::SwitchToStream " << std::endl;
1107 mFile.push_back(stream);
1108 //std::cout << " mFile.size() " << mFile.size() << std::endl;
1109 std::ostringstream buffer_name;
1111 buffer_name << "buffer_" ; // << bufferNb;
1113 // std::cout << " mFile.size() " << mFile.size() << std::endl;
1114 // std::cout << " mFileName.size() " << mFileName.size() << std::endl;
1115 // std::cout << " mLine.size() " << mLine.size() << std::endl;
1116 // std::vector<std::string>::iterator j = mFileName.begin();
1117 // std::cout << " mFileName.begin() succeeded" << std::endl;
1118 // std::cout << " mFileName[0] " << mFileName[0] << std::endl;
1119 //std::cout << " mFileName.begin() " << mFileName.begin() << std::endl;
1121 for( std::vector<std::string>::iterator i = mFileName.begin(); i!= mFileName.end(); ++i)
1124 std::cout << "Interpreter::SwitchToStream : mFileName [" << *i << "]" << std::endl;
1127 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1128 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1130 if (mFileName.size()>0 )// && (mFile.size()>0) ) // NO!!!
1132 // std::cout << " mFileName.back() " << mFileName.back() << std::endl;
1133 // std::cout << " mLine.back() " << mLine.back() << std::endl;
1134 buffer_name << mFileName.back() << "_" << mLine.back();
1136 //std::cout << "3 in Interpreter::SwitchToStream buffer_name :[" << buffer_name.str() << "]" << std::endl;
1137 mFileName.push_back(buffer_name.str());
1138 mIncludeFileName.push_back(buffer_name.str());
1142 //=======================================================================
1144 void Interpreter::LoadScript( std::string fullPathScriptName,
1145 std::string includeScriptName)
1147 Utilities::replace( fullPathScriptName , INVALID_FILE_SEPARATOR , VALID_FILE_SEPARATOR);
1149 bool okScriptExist=false;
1150 int iStrScript,sizeVecStricpt=mFileName.size();
1151 for ( iStrScript=0;iStrScript<sizeVecStricpt;iStrScript++)
1153 if (mFileName[iStrScript] == fullPathScriptName )
1159 if (find(mFileName.begin(),mFileName.end(),fullPathScriptName)!=mFileName.end())
1160 // if (okScriptExist==true)
1162 bbtkMessage("Interpreter",1,"file '"<<fullPathScriptName
1163 <<"' already open : I do not open it once more to prevent recursive inclusion"<<std::endl);
1168 s = new std::ifstream;
1169 s->open(fullPathScriptName.c_str());
1172 bbtkError("Could not open file ["<<fullPathScriptName<<"]");
1176 bbtkMessage("Interpreter",1," -->[" << fullPathScriptName
1177 << "] found" << std::endl);
1180 mFileName.push_back(fullPathScriptName);
1181 mIncludeFileName.push_back(includeScriptName);
1186 //=======================================================================
1190 void Interpreter::CloseCurrentFile()
1192 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseCurrentFile()"
1195 if (mFile.size()==0)
1197 bbtkDebugMessage("Interpreter",9," -> no file left open"<<std::endl);
1201 bbtkDebugMessage("Interpreter",9," Closing file '"<<mFileName.back()<<"'"<<std::endl);
1203 std::ifstream* file = dynamic_cast<std::ifstream*>(mFile.back());
1204 if (file!=0) file->close();
1206 delete mFile.back();
1208 mFileName.pop_back();
1209 mIncludeFileName.pop_back();
1212 bbtkDebugMessage("Interpreter",9," Remains "
1214 <<" open"<<std::endl);
1215 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseCurrentFile()"
1218 //=======================================================================
1220 //=======================================================================
1224 void Interpreter::CloseAllFiles()
1226 bbtkDebugMessage("Interpreter",9,"Interpreter::CloseAllFiles()"
1229 while (mFile.size() != 0)
1233 mFile.back()->close();
1234 delete mFile.back();
1236 bbtkDebugMessage("Interpreter",9,
1237 " Closing file '"<<mFileName.back()<<"'"<<std::endl);
1238 mFileName.pop_back();
1239 mIncludeFileName.pop_back();
1243 bbtkDebugMessage("Interpreter",9,"EO Interpreter::CloseAllFiles()"
1246 //=======================================================================
1250 //=======================================================================
1254 void Interpreter::InterpretCommand( const std::vector<std::string>& words,
1255 CommandInfoType& info )
1257 bbtkDebugMessageInc("Interpreter",9,"Interpreter::InterpretCommand(...)"<<std::endl);
1259 // searches the command category
1260 CommandDictType::iterator c;
1261 c = mCommandDict.find(words[0]);
1262 if ( c == mCommandDict.end() ) {
1263 bbtkError(words[0]<<" : unknown command");
1266 // tests the number of args
1267 if ( ( words.size()-1 < c->second.argmin ) ||
1268 ( words.size()-1 > c->second.argmax ) )
1270 HelpCommand(words[0]);
1271 bbtkError(words[0]<<" : wrong number of arguments");
1275 bbtkDecTab("Interpreter",9);
1277 //=======================================================================
1280 //=======================================================================
1281 /// Displays help on all the commands
1282 void Interpreter::Help(const std::vector<std::string>& words)
1284 unsigned int nbarg = words.size()-1;
1292 if (words[1]=="packages")
1294 GetExecuter()->GetFactory()->PrintPackages(true);
1299 HelpCommand(words[1]);
1301 catch (bbtk::Exception e)
1305 GetExecuter()->GetFactory()->HelpPackage(words[1]);
1306 #ifdef _USE_WXWIDGETS_
1307 if ( mWxConsole != 0 )
1310 ConfigurationFile::GetInstance().Get_doc_path();
1311 url += "/bbdoc/" + words[1] + "/index.html";
1312 if (Utilities::FileExists(url))
1314 mWxConsole->ShowHtmlPage(url);
1319 catch (bbtk::Exception f)
1323 std::string package;
1324 GetExecuter()->GetFactory()->HelpBlackBox(words[1],package);
1325 #ifdef _USE_WXWIDGETS_
1326 if ( mWxConsole != 0 )
1329 ConfigurationFile::GetInstance().Get_doc_path();
1330 url += "/bbdoc/" + package + "/index.html";
1331 if (Utilities::FileExists(url))
1333 url += "#" + words[1];
1334 mWxConsole->ShowHtmlPage(url);
1339 catch (bbtk::Exception g)
1343 GetExecuter()->ShowRelations(words[1],"0","9999");
1345 catch (bbtk::Exception h){
1346 bbtkError("\""<<words[1].c_str()
1347 <<"\" is not a known command, package, black box type or black box name");
1355 if (words[2]=="all")
1357 if ( words[1]=="packages" )
1359 GetExecuter()->GetFactory()->PrintPackages(true,true);
1364 GetExecuter()->GetFactory()->HelpPackage(words[1],true);
1366 catch (bbtk::Exception f)
1372 HelpCommand(words[0]);
1373 bbtkError(words[0]<<" : syntax error");
1378 bbtkError("Should not reach here !!!");
1381 //=======================================================================
1383 //===================================================================
1384 /// Displays the Configuration
1385 void Interpreter::Config() const
1387 ConfigurationFile::GetInstance().GetHelp(1);
1389 //===================================================================
1391 //=======================================================================
1392 /// Displays help on all the commands
1393 void Interpreter::HelpCommands()
1395 std::cout << "Available commands :" << std::endl;
1396 CommandDictType::iterator i;
1397 for ( i = mCommandDict.begin();
1398 i != mCommandDict.end();
1400 std::cout << " " << i->first << std::endl;
1401 // std::cout << " usage : " << i->second.syntax << std::endl;
1402 // std::cout << " " << i->second.help << std::endl;
1406 //=======================================================================
1409 //=======================================================================
1410 /// Displays help on a particular commands
1411 void Interpreter::HelpCommand(const std::string& s)
1413 CommandDictType::iterator c;
1414 c = mCommandDict.find(s);
1415 if ( c == mCommandDict.end() ) {
1416 bbtkError(s<<" : Unknown command");
1418 // std::cout << " " << s << " : "<< std::endl;
1419 // CommandParamDictType::iterator i;
1420 // for ( i = c->second.begin();
1421 // i != c->second.end();
1423 std::cout << " usage : " << c->second.syntax << std::endl;
1424 std::cout << " " << c->second.help << std::endl;
1427 //=======================================================================
1430 //=======================================================================
1431 /// Fills the vector commands with the commands which
1432 /// have the first n chars of buf for prefix
1433 /// TODO : skip initial spaces in buf and also return the position of first
1434 /// non blank char in buf
1435 void Interpreter::FindCommandsWithPrefix( char* buf,
1437 std::vector<std::string>& commands )
1439 CommandDictType::const_iterator i;
1440 for (i=mCommandDict.begin(); i!=mCommandDict.end(); ++i)
1442 if ((i->first).find(buf,0,n) == 0)
1443 commands.push_back(i->first);
1446 //=======================================================================
1450 //=======================================================================
1451 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1453 inline void PrintChar(char c) { write(STDOUT_FILENO,&c,1); }
1454 inline void BackSpace() { write(STDOUT_FILENO,"\b \b",3); }
1456 // LG : KEYBOARD CODES AS SCANNED ON MY TTY : UNIVERSAL ?
1457 // IF NOT THE USER SHOULD BE ABLE TO CONFIGURE IT
1458 // E.G. STORE THIS IN bbtk_config.xml
1459 #define BBTK_UP_ARROW_KBCODE 0x00415B1B
1460 #define BBTK_DOWN_ARROW_KBCODE 0x00425B1B
1461 #define BBTK_RIGHT_ARROW_KBCODE 0x00435B1B
1462 #define BBTK_LEFT_ARROW_KBCODE 0x00445B1B
1463 #define BBTK_BACKSPACE_KBCODE 0x00000008
1464 #define BBTK_DEL_KBCODE 0x0000007F
1465 #define BBTK_SPACE_KBCODE 0x00000020
1467 //=======================================================================
1468 void Interpreter::GetLineFromPrompt(std::string& s)
1473 int MAX_LINE_SIZE = 160;
1474 int MAX_HISTORY_SIZE = 100;
1476 char* newline = new char[MAX_LINE_SIZE];
1477 memset(newline,0,MAX_LINE_SIZE);
1478 char* histline = new char[MAX_LINE_SIZE];
1479 memset(histline,0,MAX_LINE_SIZE);
1481 char* line = newline;
1482 int hist = mHistory.size();
1488 read ( STDIN_FILENO, &c, 4) ;
1490 bbtkDebugMessage("Debug",9,"[0x"<<std::hex<<c<<"]\n");
1492 // Printable character
1493 if ( (ind<MAX_LINE_SIZE-1) &&
1494 ( c >= BBTK_SPACE_KBCODE ) &&
1495 ( c < BBTK_DEL_KBCODE ))
1503 // delete the unused line
1509 // empty lines are not stored in from history
1512 // if history too long : delete oldest command
1513 if (mHistory.size()>MAX_HISTORY_SIZE)
1515 delete mHistory.front();
1516 mHistory.pop_front();
1518 mHistory.push_back(line);
1523 else if ( (ind>0) &&
1524 ((c == BBTK_BACKSPACE_KBCODE) ||
1525 (c == BBTK_DEL_KBCODE)) )
1533 // TODO : Command completion
1534 std::vector<std::string> commands;
1535 FindCommandsWithPrefix( line,ind,commands);
1536 if (commands.size()==1)
1538 std::string com = *commands.begin();
1539 for (; ind<com.size(); ++ind)
1541 PrintChar(com[ind]);
1547 else if (commands.size()>1)
1549 std::vector<std::string>::iterator i;
1551 for (i=commands.begin();i!=commands.end();++i)
1553 write(STDOUT_FILENO,(*i).c_str(),strlen((*i).c_str()));
1556 write(STDOUT_FILENO,"\n> ",3);
1557 //for (int j=0;j<ind;++j)
1559 write(STDOUT_FILENO,line,ind);
1563 // Arrow up : back in history
1564 else if (c==BBTK_UP_ARROW_KBCODE)
1568 // erase current line
1569 while (ind--) BackSpace();
1573 strcpy(histline,mHistory[hist]);
1577 write(STDOUT_FILENO,line,ind);
1580 // Arrow down : down in history
1581 else if (c==BBTK_DOWN_ARROW_KBCODE)
1583 if (hist<mHistory.size()-1)
1585 // erase current line
1586 while (ind--) BackSpace();
1590 strcpy(histline,mHistory[hist]);
1594 write(STDOUT_FILENO,line,ind);
1596 // end of history : switch back to newline
1597 else if (hist==mHistory.size()-1)
1599 // erase current line
1600 while (ind--) BackSpace();
1607 write(STDOUT_FILENO,line,ind);
1611 else if (line[ind]!=0 && c==BBTK_RIGHT_ARROW_KBCODE)
1613 PrintChar(line[ind]);
1618 else if (ind>0 && c==BBTK_LEFT_ARROW_KBCODE)
1626 write(STDOUT_FILENO,"\n\r",2);
1634 //=======================================================================
1635 void Interpreter::GetLineFromPrompt(std::string& s)
1661 //=======================================================================
1667 //=======================================================================
1668 void Interpreter::CommandLineInterpreter()
1670 bbtkDebugMessageInc("Interpreter",9,
1671 "Interpreter::CommandLineInterpreter()"<<std::endl);
1673 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1674 // Initialise the tty in non canonical mode with no echo
1675 // oter remembers the previous settings to restore them after
1676 struct termios ter,oter;
1679 ter.c_lflag &= ~ECHO;
1680 ter.c_lflag &= ~ICANON;
1683 tcsetattr(0,TCSANOW,&ter);
1686 mCommandLine = true;
1688 bool insideComment = false; // for multiline comment
1694 GetLineFromPrompt(line);
1695 InterpretLine(line, insideComment);
1697 catch (QuitException e)
1701 catch (bbtk::Exception e)
1705 catch (std::exception& e)
1707 std::cerr << "* ERROR :: "<<e.what()<<" (not in bbtk)"<<std::endl;
1711 std::cerr << "* UNDEFINED ERROR (not a bbtk nor a std exception)"<<std::endl;
1716 #ifdef BBTK_USE_TERMIOS_BASED_PROMPT
1717 tcsetattr(0,TCSANOW,&oter);
1720 std::cout << "Good bye !" << std::endl;
1722 bbtkDebugDecTab("Interpreter",9);
1725 //=======================================================================
1726 void Interpreter::Graph(const std::vector<std::string>& words)
1729 bool system_display = true;
1731 #ifdef _USE_WXWIDGETS_
1732 if ( mWxConsole != 0 ) system_display = false;
1735 if (words.size()==1)
1737 page = mExecuter->ShowGraph(".","0","0","","","",system_display);
1739 else if (words.size()==2)
1741 page = mExecuter->ShowGraph(words[1],"0","0","","","",system_display);
1743 else if (words.size()==3)
1745 page = mExecuter->ShowGraph(words[1],words[2],"0","","","",system_display);
1747 else if (words.size()==4)
1749 page = mExecuter->ShowGraph(words[1],words[2],words[3],"","","",system_display);
1751 else if (words.size()==5)
1753 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],"","",system_display);
1755 else if (words.size()==6)
1757 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],"",system_display);
1759 else if (words.size()==7)
1761 page = mExecuter->ShowGraph(words[1],words[2],words[3],words[4],words[5],words[6],system_display);
1764 #ifdef _USE_WXWIDGETS_
1765 if ( mWxConsole != 0 )
1766 mWxConsole->ShowHtmlPage(page);
1769 //=======================================================================
1772 //=======================================================================
1773 void Interpreter::Index(const std::string& filename,
1774 const std::string& type)
1776 Factory::IndexEntryType t;
1777 if (type=="Initials") t = Factory::Initials;
1778 else if (type=="Categories") t = Factory::Categories;
1779 else if (type=="Packages") t = Factory::Packages;
1780 else if (type=="Adaptors") t = Factory::Adaptors;
1782 GetExecuter()->GetFactory()->CreateHtmlIndex(t,filename);
1784 //=======================================================================