#include "commander.h" #include #include #include #include #include #include "strutil.h" #include "strutilxx.h" #include "cexpre.h" #include "rpneval.h" #include "srandgen.h" namespace SOPHYA { // Differents code de retour specifiques #define CMD_RETURN_RC 99900 #define CMD_BREAK_RC 99990 #define CMD_BREAKEXE_RC 99999 // ------------------------------------------------------------ // Bloc de commandes (Foreach, ...) // Classe CommanderBloc // ------------------------------------------------------------ /*! \internal \class SOPHYA::CommanderBloc \ingroup SysTools Class for internal use by class Commander to handle loops */ class CommanderBloc { public: enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat, BT_ForeachLineInFile }; CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector& args); ~CommanderBloc(); inline CommanderBloc* Parent() { return(parent); } inline bool CheckOK() { return blkok; } inline void AddLine(string& line) { lines.push_back(line); bloclineid.push_back(lines.size()); } void AddLine(string& line, string& kw); inline void AddBloc(CommanderBloc* blk) { blocs.push_back(blk); bloclineid.push_back(-blocs.size()); } // Execution complete du bloc (boucle) int Execute(); // Execution pour un element de bloc int ExecuteOnce(string& lvv); inline int& TestLevel() { return testlevel; } inline int& LoopLevel() { return looplevel; } inline bool CheckBloc() { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)); } protected: Commander* _commander; CommanderBloc* parent; bool blkok; // true -> block OK BType typ; // foreach , integer loop, float loop, test string varname; string filename; // forinfile bloc vector strlist; vector lines; vector blocs; vector bloclineid; int i1,i2,di; float f1,f2,df; int testlevel; // niveau d'imbrication des if int looplevel; // niveau d'imbrication des for/foreach bool scrdef; // true -> commande defscript ds for/foreach }; /* --Methode-- */ CommanderBloc::CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector& args) { _commander = piac; parent = par; blkok = false; typ = BT_None; i1 = 0; i2 = -1; di = 1; f1 = 0.; f2 = -1.; df = 1.; testlevel = looplevel = 0; scrdef = false; if ((args.size() < 2) || !isalpha((int)args[0][0]) ) return; if ((kw != "foreach") && (kw != "for") && (kw != "forinfile")) return; if (!piac->CheckVarName(args[0])) return; varname = args[0]; //if (isalpha((int)args[1][0]) ) { This is a foreach bloc with string list if (kw == "forinfile") { filename = args[1]; typ = BT_ForeachLineInFile; blkok = true; } else if (kw == "foreach" ) { // This is a foreach bloc with string list if ( (args[1] == "(") && (args[args.size()-1] == ")") ) { // foreach varname ( w1 w2 w3 ... ) for(int kk=2; kkGetVar(args[1], strlist)) return; } if (strlist.size() < 1) return; typ = BT_ForeachList; blkok = true; } else { // This is an integer or float loop size_t l = args[1].length(); size_t p = args[1].find(':'); size_t pp = args[1].find('.'); bool fl = (pp < l) ? true : false; // Float loop or integer loop if (p >= l) return; // Syntaxe error string a1 = args[1].substr(0, p); string aa = args[1].substr(p+1); p = aa.find(':'); string a2, a3; bool hasa3 = false; if (p < aa.length() ) { a2 = aa.substr(0,p); a3 = aa.substr(p+1); hasa3 = true; } else a2 = aa; if (fl) { typ = BT_ForeachFloat; blkok = true; f1 = atof(a1.c_str()); f2 = atof(a2.c_str()); if (hasa3) df = atof(a3.c_str()); else df = 1.; } else { typ = BT_ForeachInt; blkok = true; i1 = atoi(a1.c_str()); i2 = atoi(a2.c_str()); if (hasa3) di = atoi(a3.c_str()); else di = 1; } } } /* --Methode-- */ CommanderBloc::~CommanderBloc() { for(int k=0; kGetMaxLoopLimit(); if (typ == BT_ForeachLineInFile) { // foreach line in file loop ifstream is(filename.c_str()); char buff[256]; string line; while (!is.eof()) { rcc = 0; is.clear(); is.getline(buff, 256); line += buff; if (is.good()) { rcc = ExecuteOnce(line); line = ""; } if (rcc == CMD_BREAKEXE_RC) return rcc; else if (rcc == CMD_BREAK_RC) break; } } else if (typ == BT_ForeachList) { // foreach string loop for(k=0; k0) && (k > mxloop)) { cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl; break; } sprintf(buff, "%d", i); string lvv = buff; rcc = ExecuteOnce(lvv); if (rcc == CMD_BREAKEXE_RC) return rcc; else if (rcc == CMD_BREAK_RC) break; } } else if (typ == BT_ForeachFloat) { // float loop for(double f=f1; f0) && (k > mxloop)) { cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl; break; } sprintf(buff, "%g", f); string lvv = buff; rcc = ExecuteOnce(lvv); if (rcc == CMD_BREAKEXE_RC) return rcc; else if (rcc == CMD_BREAK_RC) break; } } return(rcc); } /* --Methode-- */ int CommanderBloc::ExecuteOnce(string& lvv) { int kj=0; int kk=0; int rcc = 0; _commander->SetVar(varname, lvv); for(kj=0; kj 0) rcc = _commander->Interpret(lines[kk-1]); else rcc = blocs[-kk-1]->Execute(); if (rcc == CMD_BREAKEXE_RC) return (rcc); if (rcc == CMD_BREAK_RC) break; } return rcc; } // --------------------------------------------------------------- // Classe CommanderScript // Definition et execution d'un script de Commander // script : Une liste de commande Commander - Lors de l'execution, // les variables-argument $# $0 $1 sont definies. // --------------------------------------------------------------- /*! \internal \class SOPHYA::CommanderScript \ingroup SysTools Class for internal use by class Commander to handle functions or scripts */ class CommanderScript { public: CommanderScript(Commander* piac, string const& name, string const& comm); virtual ~CommanderScript(); void AddLine(string& line, string& kw); virtual int Execute(vector& args); inline string& Name() { return mName; } inline string& Comment() { return mComm; } inline int& TestLevel() { return testlevel; } inline int& LoopLevel() { return looplevel; } inline bool CheckScript() { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)&&fgok); } protected: Commander* _commander; string mName; string mComm; vector lines; int testlevel; // niveau d'imbrication des if int looplevel; // niveau d'imbrication des for/foreach bool scrdef; // true -> commande defscript ds for/foreach bool fgok; // Script name OK }; /* --Methode-- */ CommanderScript::CommanderScript(Commander* piac, string const& name, string const& comm) { _commander = piac; testlevel = looplevel = 0; scrdef = false; mName = name; if (!isalpha(name[0])) fgok = false; else fgok = true; mComm = comm; } /* --Methode-- */ CommanderScript::~CommanderScript() { } /* --Methode-- */ void CommanderScript::AddLine(string& line, string& kw) { if (kw == "if") testlevel++; else if (kw == "endif") testlevel--; else if ((kw == "for") || (kw == "foreach")) looplevel++; else if (kw == "end") looplevel--; else if (kw == "defscript") scrdef = true; lines.push_back(line); } /* --Methode-- */ int CommanderScript::Execute(vector& args) { int rcc; if (!CheckScript()) return(-1); cout << " CommanderScript::Execute() - Executing script " << Name() << endl; for(int k=0; kInterpret(lines[k]); if ( (rcc == CMD_BREAKEXE_RC) || (rcc == CMD_RETURN_RC) ) break; } return(rcc); } // ------------------------------------------------------------ // Classe Commander // ------------------------------------------------------------ typedef void (* DlModuleInitEndFunction) (); /*! \class Commander \ingroup SysTools \brief Simple command interpreter This Simple command interpreter with c-shell like syntax can be used to add scripting capabilities to applications. Although the insterpreter has many limitations compared to c-shell, or Tcl , it provides some interesting possibilities: - Extended arithmetic operations (c-like and RPN) - Simple and vector variables - Script definition - Dynamic Load \sa CmdExecutor CExpressionEvaluator RPNExpressionEvaluator Usage example: \code #include "commander.h" ... Commander cmd; char* ss[3] = {"foreach f ( AA bbb CCCC ddddd )", "echo $f" , "end"}; for(int k=0; k<3; k++) { string line = ss[k]; cmd.Interpret(line); } \endcode */ #define _MAGENTA_ 1 static Commander* cur_commander = NULL; /* --Methode-- */ //! Default constructor. Initializes variable list and copies \c history.pic to \c hisold.pic Commander::Commander() { system("cp history.pic hisold.pic"); hist.open("history.pic"); histon = true; trace = false; timing = false; gltimer = NULL; felevel = 0; mulinecmd = ""; mulinefg = false; spromptmul = "Cmd> "; SetCurrentPrompt(spromptmul); SetDefaultPrompt(spromptmul); curscript = NULL; _xstatus = 0; _retstr = ""; // Controle du flot d'execution fgexebrk = false; CmdBlks.push(NULL); list xtx; TestsStack.push(xtx); curtestresult = true; // Numero de help-groupe courant - Le premier groupe ajoute aura un gid = 1 // gid = 0 n'existe pas : c'est le groupe de toutes les commandes cmdgrpid = 0; string grp = "Commander"; string gdesc = "Basic (generic) interpreter (class SOPHYA::Commander) builtin commands"; AddHelpGroup(grp, gdesc); string kw = "Commander"; string usage; usage = ">>> (Commander) Interpreter's keywords : \n"; usage += " > set varname string # To set a variable, $varname \n"; usage += " > unset varname # clear variable definition \n"; usage += " > rpneval varname RPNExpression # Reverse Polish Notation evaluation \n"; usage += " > varname = ArithmeticExpression # C-like Expression evaluation \n"; usage += " > varname = 'String' # Set variable vname \n"; usage += " > var2words varname wordvarname [sep] # to break varname into words \n"; usage += " > echo string # output string \n"; usage += " > echo2file filename string # Append the string to the specified file \n"; usage += " > alias name string # define a command alias \n"; usage += " > foreach varname ( string-list ) # Loop \n"; usage += " > for varname i1:i2[:di] # Integer loop \n"; usage += " > for varname f1:f2[:df] # Float loop \n"; usage += " > forinfile varname FileName # Loop over lines in file \n"; usage += " > end # end loops \n"; usage += " > if ( test ) then # Conditional test : a == != < > <= >= b \n"; usage += " > else # Conditional \n"; usage += " > endif # End of conditional if bloc \n"; usage += " > break # Delete (clears) all test and loop blocs \n"; usage += " > return # Stops command execution from a file \n"; usage += " > defscript endscript # Command script definition \n"; usage += " > listvars # List of variable names and values \n"; usage += " > listalias # List of alias names and values \n"; usage += " > listcommands # List of all known commands \n"; usage += " > listscripts # List of all known scripts \n"; usage += " > clearcript # Clear a script definition \n"; usage += " > exec filename # Execute commands from file \n"; usage += " > help # usage info \n"; usage += " > sleep nsec # sleep nsec seconds \n"; usage += " > readstdin varname # reads a line from stdin into $varname \n"; usage += " > timingon timingoff traceon traceoff \n"; RegisterHelp(kw, usage, grp); kw = "RPNEvaluator"; usage = " Reverse Polish Notation (HP calculator like) expression evaluation \n"; usage += " >> Stack: \n"; usage += " ... (4) (3) z=(2) y=(1) x=(0)=Stack.Top() \n"; usage += " >> Examples: \n"; usage += " - sin(PI/6): pi 6 / sin \n"; usage += " - 1*2*...*5: 1 2 3 4 5 product \n"; usage += " - x=x+y: x = $x $y * \n"; usage += " >>> Stack operations : \n"; usage += " print x<>y pop push (duplicate x) \n"; usage += " >>> Constants (Cst pushed to stack): \n"; usage += " pi e \n"; usage += " >>> Arithmetic operators (x,y) --> x@y \n"; usage += " + - * / % ( (int)y % (int)x )\n"; usage += " >>> F(X): x --> F(x) \n"; usage += " chs sqrt sq log log10 exp \n"; usage += " fabs floor ceil \n"; usage += " cos sin tan acos asin atan deg2rad rad2deg \n"; usage += " >>> F(X,Y): (x,y) --> F(x,y) \n"; usage += " pow atan2 \n"; usage += " >>> F(): random number generators \n"; usage += " rand (flat 0..1) norand (normal/gaussian) \n"; usage += " >>> Stack sum/product/mean/sigma/sigma^2 \n"; usage += " sum product mean sigma sigma2 sigmean (y->sigma x->mean) \n"; RegisterHelp(kw, usage, grp); kw = "autoiniranf"; usage = "> Automatic random number generator initialisation\n"; usage += " by Auto_Ini_Ranf(int lp) \n"; usage += " Usage: autoiniranf"; RegisterCommand(kw, usage, NULL, grp); kw = "shell execute"; usage = "> shell command_string # Execute shell command\n"; usage += "> cshell command_string # Execute cshell command\n"; usage += "---Examples:\n"; usage += " > shell ls\n"; usage += " > cshell echo '$LD_LIBRARY_PATH'; map2cl -h; ls\n"; usage += " > shell myfile.csh [arg1] [arg2] [...]\n"; usage += " (where the first line of \"myfile.csh\" is \"#!/bin/csh\")\n"; RegisterCommand(kw, usage, NULL, grp); AddInterpreter(this); curcmdi = this; } /* --Methode-- */ Commander::~Commander() { hist.close(); if (gltimer) { delete gltimer; gltimer = NULL; } Modmap::iterator it; for(it = modmap.begin(); it != modmap.end(); it++) { string name = (*it).first + "_end"; DlModuleInitEndFunction fend = (*it).second->GetFunction(name); if (fend) fend(); delete (*it).second; } for(ScriptList::iterator sit = mScripts.begin(); sit != mScripts.end(); sit++) delete (*sit).second; if (cur_commander == this) cur_commander = NULL; } /* --Methode-- */ Commander* Commander::GetInterpreter() { return(cur_commander); } /* --Methode-- */ //! Returns the string \c Commander as the interpreter's name. string Commander::Name() { return("Commander"); } /* --Methode-- */ //! Add the \b grp help group with description \b desc. void Commander::AddHelpGroup(string& grp, string& desc) { int gid; CheckHelpGrp(grp, gid, desc); } /* --Methode-- */ /*! \brief Register a command executor associated with a given keyword. \param keyw : keyword identifying the command \param usage : the command help and usage information \param ce : CmdExecutor pointer for this a command. The same object can be registered multiple time for different commands. \param grp : The help group corresponding to this command. */ void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string& grp) { if (!ce) { RegisterHelp(keyw, usage, grp); return; } int gid; CheckHelpGrp(grp,gid); cmdex cme; cme.group = gid; cme.us = usage; cme.cex = ce; cmdexmap[keyw] = cme; } /* --Methode-- */ /*! \brief Register a help text. \param keyw : help keyword \param usage : help text \param grp : help group */ void Commander::RegisterHelp(string& keyw, string& usage, string& grp) { int gid; CheckHelpGrp(grp,gid); cmdex cme; cme.group = gid; cme.us = usage; cme.cex = NULL; helpexmap[keyw] = cme; } /* --Methode-- */ bool Commander::CheckHelpGrp(string& grp, int& gid, string& desc) { gid = 0; CmdHGroup::iterator it = cmdhgrp.find(grp); if (it == cmdhgrp.end()) { cmdgrpid++; gid = cmdgrpid; hgrpst hgs; hgs.gid = gid; hgs.desc = desc; cmdhgrp[grp] = hgs; return true; } else { if (desc.length() > 0) (*it).second.desc = desc; gid = (*it).second.gid; return false; } } /* --Methode-- */ /*! \brief Dynamic loader for modules A module is a shared library extending the application functionalities. Typically, a module adds new commands to the interpreter. Once loaded, the module is activated (initialized) by calling a function with the name \b modulename_init . This function should be declared extern C to avoid C++ name mangling. A cleanup function \b modulename_end is called by the Commander destructor. \param fnameso : Shared library name containing the module functions and classes. \param name : Module name. This string is used to form module initializer and cleanup function name \c name_init \c name_end */ void Commander::LoadModule(string& fnameso, string& name) { PDynLinkMgr * dynlink = new PDynLinkMgr(fnameso, false); if (dynlink == NULL) { cerr << "Commander/LoadModule_Error: Pb opening SO " << fnameso << endl; return; } string fname = name + "_init"; DlModuleInitEndFunction finit = dynlink->GetFunction(fname); if (!finit) { cerr << "Commander/LoadModule_Error: Pb linking " << fname << endl; return; } cout << "Commander/LoadModule_Info: Initialisation module" << name << " " << fname << "() ..." << endl; finit(); modmap[name] = dynlink; return; } /* --Methode-- */ //! Declare a new interpreter void Commander::AddInterpreter(CmdInterpreter * cl) { if (!cl) return; interpmap[cl->Name()] = cl;} /* --Methode-- */ //! Select an interpreter by its name. The corresponding Interpret method is then called void Commander::SelInterpreter(string& name) { InterpMap::iterator it = interpmap.find(name); if (it == interpmap.end()) return; curcmdi = (*it).second; } /* Fonction */ static string GetStringFrStdin(Commander* piac) { char buff[128]; fgets(buff, 128, stdin); buff[127] = '\0'; return((string)buff); } /* --Methode-- */ /*! \brief Method which has to be invoked to interpret a giev command line or string. */ int Commander::Interpret(string& s) { int rc = 0; ScriptList::iterator sit; // On saute de commandes vides size_t l; l = s.length(); if (!mulinefg && (l < 1)) return(0); // On enregistre les commandes if (histon) hist << s << endl; if (s[0] == '#') return(0); // si c'est un commentaire // Logique de gestion des lignes suite // un \ en derniere position indique la presence d'une ligne suite size_t lnb = s.find_last_not_of(' '); if (s[lnb] == '\\' ) { // Lignes suite ... mulinecmd += s.substr(0,lnb); if (!mulinefg) { spromptmul = GetCurrentPrompt(); SetCurrentPrompt("...? "); mulinefg = true; } return(0); } if (mulinefg) { // Il y avait des lignes suite s = mulinecmd + s; l = s.length(); mulinecmd = ""; mulinefg = false; SetCurrentPrompt(spromptmul); } // Removing leading blanks size_t p,q; // On enleve le dernier caractere, si celui-ci est \n if (s[l-1] == '\n') s[l-1] = '\0'; p=s.find_first_not_of(" \t"); if (p < l) s = s.substr(p); // >>>> Substitution d'alias (1er mot) CmdStrList::iterator it; p = 0; q = s.find_first_of(" \t"); l = s.length(); string w1 = (q < l) ? s.substr(p,q-p) : s.substr(p); it = mAliases.find(w1); if (it != mAliases.end()) { s = (q < l) ? ((*it).second + s.substr(q)) : (*it).second ; l = s.length(); p=s.find_first_not_of(" \t"); if (p < l) s = s.substr(p); p = 0; q = s.find_first_of(" "); } // >>>> Separating keyword string toks,kw; if (q < l) { kw = s.substr(p,q-p); toks = s.substr(q, l-q); } else { kw = s.substr(p,l-p); toks = ""; } // les mot-cle end else endif doivent etre le seul mot de la ligne if ( (kw == "end") || (kw == "else") || (kw == "endif") || (kw == "endscript") ) { size_t ltk = toks.length(); if (toks.find_first_not_of(" \t") < ltk) { cerr << "Commander::Interpret()/syntax error near end else endif endscript \n" << "line: " << s << endl; _xstatus = 91; return(91); } } // On verifie si on est en train de definir un script if (curscript) { if (kw == "endscript") { if (curscript->CheckScript()) { sit = mScripts.find(curscript->Name()); if (sit != mScripts.end()) { cout << "Commander::Interpret() replacing script " << curscript->Name() << endl; CommanderScript* scr = mScripts[curscript->Name()]; mScripts.erase(sit); delete scr; } cout << "Commander::Interpret() Script " << curscript->Name() << " defined successfully" << endl; mScripts[curscript->Name()] = curscript; SetCurrentPrompt("Cmd> "); curscript = NULL; _xstatus = 0; return(0); } else { cout << "Commander::Interpret() Error in Script " << curscript->Name() << " definition " << endl; SetCurrentPrompt("Cmd> "); curscript = NULL; _xstatus = 92; return(92); } } else curscript->AddLine(s, kw); _xstatus = 0; return(0); } // On verifie si nous sommes dans un bloc (for , foreach) if (CmdBlks.top() != NULL) { // On est dans un bloc if ( (kw == "for") || (kw == "foreach")) felevel++; else if (kw == "end") felevel--; if (felevel == 0) { // Il faut executer le bloc CommanderBloc* curb = CmdBlks.top(); CmdBlks.top() = curb->Parent(); SetCurrentPrompt("Cmd> "); if (!curb->CheckBloc()) { cerr << "Commander::Interpret()/syntax error - unbalenced if ... endif" << " within for/foreach bloc ! " << endl; delete curb; _xstatus = 93; return(93); } // cout << " *DBG* Executing bloc " << endl; bool ohv = histon; histon = false; if (curtestresult) { // We push also CommanderBloc and testresult on the stack CmdBlks.push(NULL); list xtx; TestsStack.push(xtx); curb->Execute(); // And CommanderBloc and TestResult from the corresponding stacks PopStack(false); } SetCurrentPrompt(defprompt); delete curb; histon = ohv; } else CmdBlks.top()->AddLine(s, kw); _xstatus = 0; return(0); } else if (kw == "end") { cerr << "Commander::Interpret()/syntax error - end outside for/foreach bloc \n" << "line: " << s << endl; _xstatus = 94; return(94); } // Sommes-nous dans un bloc de test if then else if (TestsStack.top().size() > 0) { // Nous sommes ds un bloc if if (kw == "else") { if ((*tresit) & 2) { cerr << "Commander::Interpret()/syntax error - multiple else in if bloc \n" << "line: " << s << endl; _xstatus = 95; return(95); } else { const char * npr = ((*tresit)&1) ? "else-F> " : "else-T> "; if ((*tresit)&1) curtestresult = false; SetCurrentPrompt(npr); (*tresit) |= 2; _xstatus = 0; return(0); } } else if (kw == "endif") { list::iterator dbit = tresit; tresit--; TestsStack.top().erase(dbit); const char * npr = "Cmd> "; if (TestsStack.top().size() > 1) { curtestresult = true; list::iterator it; for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) { // Si on n'est pas ds le else et le if est faux if ( !((*it)&2) && !((*it)&1) ) curtestresult = false; // Si on est ds else et le if etait vrai ! if ( ((*it)&2) && ((*it)&1) ) curtestresult = false; if (!curtestresult) break; } if (!((*tresit)&2)) npr = ((*tresit)&1) ? "if-T> " : "if-F> "; else npr = ((*tresit)&1) ? "else-F> " : "else-T> "; } else curtestresult = true; SetCurrentPrompt(npr); _xstatus = 0; return(0); } } else if ((kw == "else") || (kw == "endif")) { cerr << "Commander::Interpret()/syntax error - else,endif outside if bloc \n" << "line: " << s << endl; _xstatus = 91; return(91); } bool fgcont = true; if (TestsStack.top().size() > 0) { // Resultat de if ou else list::iterator it; for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) { // Si on n'est pas ds le else et le if est faux if ( !((*it)&2) && !((*it)&1) ) fgcont = false; // Si on est ds else et le if etait vrai ! if ( ((*it)&2) && ((*it)&1) ) fgcont = false; if (!fgcont) break; } } if ((!fgcont) && (kw != "if")) { _xstatus = 0; return(0); } // Les mots cles break et return peuvent de sortir de boucles/scripts/execfile if (kw == "break") return CMD_BREAK_RC; else if (kw == "return") { _retstr = toks; return CMD_RETURN_RC; } // Nous ne sommes donc pas dans un bloc .... Substitution de variables string s2; int rcs ; rcs = SubstituteVars(s, s2); if (rcs) { cerr << "Commander::Interpret()/syntax error in SubstituteVars() \n" << "line: " << s << endl; _xstatus = 99; return(99); } // >>>> Separating keyword and tokens vector tokens; vector qottoks; /* decoupage en mots */ LineToWords(s2, kw, tokens, qottoks, toks, true); // Si c'est un for/foreach, on cree un nouveau bloc if ((kw == "foreach") || (kw == "for") || (kw == "forinfile") ) { // cout << " *DBG* We got a foreach... " << endl; CommanderBloc* bloc = new CommanderBloc(this, CmdBlks.top(), kw, tokens); if (!bloc->CheckOK()) { cerr << "Commander::Interpret() for/foreach syntax Error ! " << endl; delete bloc; _xstatus = 91; return(91); } felevel++; if (CmdBlks.top()) CmdBlks.top()->AddBloc(bloc); else SetCurrentPrompt("for...> "); CmdBlks.top() = bloc; // cout << " *DBG* New Bloc created ... " << endl; return(0); } else if (kw == "if") { // Un test if bool restst = true; int rct = EvaluateTest(tokens, s, restst); if (rct) { cerr << "Commander::Interpret() if syntax Error ! " << "line: " << s << endl; _xstatus = 91; return(91); } char res_tst = (restst) ? 1 : 0; TestsStack.top().push_back(res_tst); if (TestsStack.top().size() == 1) tresit = TestsStack.top().begin(); else tresit++; const char * npr = (restst) ? "if-T> " : "if-F> "; SetCurrentPrompt(npr); } else if ((tokens.size() > 0) && (tokens[0] == "=")) { // x = Expression if (qottoks[1]) { // decodage sous forme de chaine SetVariable(kw, tokens[1]); } else { try { double res = 0.; if (tokens.size() > 2) { string sex = tokens[1]; for(int js=2; js 0) { if (tokens.size() < 2) tokens.push_back(""); curscript = new CommanderScript(this, tokens[0], tokens[1]); SetCurrentPrompt("Script...> "); return(0); } else { cerr << "Commander::Interpret() No script name in defscript" << "line: " << s << endl; _xstatus = 91; return(91); } } else { // Si c'est le nom d'un script sit = mScripts.find(kw); if (sit != mScripts.end()) { bool ohv = histon; histon = false; tokens.insert(tokens.begin(), kw); PushStack(tokens); (*sit).second->Execute(tokens); PopStack(true); histon = ohv; } // Execution de commandes else rc = ExecuteCommandLine(kw, tokens, toks); _xstatus = rc; return(rc); } // cout << "Commander::Do() DBG KeyW= " << kw << " NbArgs= " << tokens.size() << endl; // for(int ii=0; ii& tokens, vector& qottoks, string& toks, bool uq) { if (line.length() < 1) return(0); int nw = 1; size_t p = line.find_first_not_of(" "); line = line.substr(p); p = 0; size_t q = line.find_first_of(" "); size_t l = line.length(); if (q < l) { kw = line.substr(p,q-p); toks = line.substr(q, l-q); } else { kw = line.substr(p,l-p); toks = ""; } q = 0; while (q < l) { bool swq = false; // true -> chaine delimite par ' ou " p = toks.find_first_not_of(" \t",q+1); // au debut d'un token if (p>=l) break; if ( uq && ((toks[p] == '\'') || (toks[p] == '"')) ) { q = toks.find(toks[p],p+1); if (q>=l) { cerr << "Commander::LineToWords/Syntax Error - Unbalenced quotes " << toks[p] << '.' << endl; return(-1); } p++; swq = true; } else { q = toks.find_first_of(" \t",p); // la fin du token; } string token = toks.substr(p,q-p); tokens.push_back(token); qottoks.push_back(swq); nw++; } return(nw); } /* --Methode-- */ int Commander::SubstituteVars(string & s, string & s2) // Variable substitution { int iarr = -1; // index d'element de tableau size_t p,q,q2,q3,l; s2=""; p = 0; l = s.length(); string vn, vv; while (p < l) { iarr = -1; q = s.find('$',p); if (q > l) break; q2 = s.find('\'',p); if ((q2 < l) && (q2 < q)) { // On saute la chaine delimitee par ' ' q2 = s.find('\'',q2+1); if (q2 >= l) { cerr << " Syntax error - Unbalenced quotes !!! " << endl; return(1); } s2 += s.substr(p, q2-p+1); p = q2+1; continue; } // cout << "DBG: " << s2 << " p= " << p << " q= " << q << " L= " << l << endl; if ((q>0) && (s[q-1] == '\\')) { // Escape character \$ s2 += (s.substr(p,q-1-p) + '$') ; p = q+1; continue; } if (q >= l-1) { cerr << " Syntax error - line ending with $ !!! " << endl; return(2); } vn = ""; if ( s[q+1] == '{' ) { // Variable in the form ${name} q2 = s.find('}',q+1); if (q2 >= l) { cerr << " Syntax error - Unbalenced brace {} !!! " << endl; return(3); } vn = s.substr(q+2,q2-q-2); q2++; } else if ( s[q+1] == '(' ) { // Variable in the form $(name) q2 = s.find(')',q+1); if (q2 >= l) { cerr << " Syntax error - Unbalenced parenthesis () !!! " << endl; return(3); } vn = s.substr(q+2,q2-q-2); q2++; } else if ( s[q+1] == '[' ) { // Variable in the form $[varname] -> This is $$varname q2 = s.find(']',q+1); if (q2 >= l) { cerr << " Syntax error - Unbalenced brace [] !!! " << endl; return(4); } vn = s.substr(q+2,q2-q-2); if (!Var2Str(vn, vv)) return(5); vn = vv; q2++; } else { q2 = s.find_first_of(" .:+-*/,[](){}&|!$\"'",q+1); if (q2 > l) q2 = l; q3 = q2; vn = s.substr(q+1, q2-q-1); // Si variable de type $varname[index] : element de tableau if ((q2 < l) && (s[q2] == '[') ) { q3 = s.find_first_of("]",q2+1); string sia = s.substr(q2+1, q3-q2-1); if (sia.length() < 1) { cerr << " Syntax error - in $varname[index] : $" << vn << "[" << sia <<"]" << endl; return(4); } if (isalpha(sia[0])) { string sia2; if (!Var2Str(sia, sia2) || (sia2.length() < 1)) { cerr << " Syntax error - in $varname[index] : $" << vn << "[" << sia <<"]" << endl; return(4); } sia = sia2; } int rcdia = ctoi(sia.c_str(), &iarr); if (rcdia < 0) { cerr << " Syntax error - in $varname[iarr] : $" << vn << "[" << sia <<"]" << endl; return(4); } } } if (iarr < 0) { if (!Var2Str(vn, vv)) return(5); s2 += (s.substr(p, q-p) + vv); p = q2; } else { if (! Var2Str(vn, iarr, vv) ) { cerr << " Substitution error - word index out of range in " << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl; return(4); } else s2 += (s.substr(p, q-p) + vv); p = q3+1; } } if (p < l) s2 += s.substr(p); p = s2.find_first_not_of(" \t"); if (p < l) s2 = s2.substr(p); return(0); } /* --Methode-- */ bool Commander::Var2Str(string const & vn, string & vv) { if (vn.length() < 1) { cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl; vv = ""; return(false); } // Variable de type $# $0 $1 ... (argument de .pic ou de script) int ka = 0; char buff[32]; if (vn == "#") { if (ArgsStack.empty()) { cerr << " Commander::Var2Str/Error: ArgsStack empty ! " << " ($" << vn << ")" << endl; vv = ""; return(false); } char buff[32]; long an = ArgsStack.top().size(); if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0 sprintf(buff,"%ld", an); vv = buff; return(true); } else if (vn == "*") { if (ArgsStack.empty()) { cerr << " Commander::Var2Str/Error: ArgsStack empty ! " << " ($" << vn << ")" << endl; vv = ""; return(false); } vv = ArgsStack.top()[0]; for(int ssk=1; ssk 0) { // $0 $1 $2 ... if (ArgsStack.empty()) { cerr << " Commander::Var2Str/Error: ArgsStack empty ! " << " ($" << vn << ")" << endl; vv = ""; return(false); } if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) { cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! " << " ($" << vn << ")" << endl; vv = ""; return(false); } vv = ArgsStack.top()[ka]; return(true); } else if (vn[0] == '#') { // Variable de type $#vname --> size(vname) CmdVarList::iterator it = variables.find(vn.substr(1)); if (it == variables.end()) { cerr << " Commander::Var2Str/Error #vname Undefined variable " << vn << " ! " << endl; vv = ""; return(false); } sprintf(buff,"%d", (int)(*it).second.size()); vv = buff; return(true); } else if (vn == "status") { sprintf(buff,"%d", _xstatus); vv = buff; return true; } else if ((vn == "retstr") || (vn == "retval")) { vv = _retstr; return true; } else { // Variable de l'interpreteur, ou de l'environnement application , env. global if (GetVar(vn, vv)) return true; else if (GetVarApp(vn, vv)) return true; else if (GetVarEnv(vn, vv)) return true; else { cerr << " Commander::Var2Str/Error Undefined variable " << vn << " ! " << endl; vv = ""; return false; } } return false; } /* --Methode-- */ bool Commander::SetVariable(string const & vn, string const & vv) { // On verifie si le nom est de type vname[idx] size_t p,q,l; l = vn.length(); p = vn.find('['); if (p < l) { q = vn.find(']'); if (q != (l-1)) { cout << "Commander::Str2Var/SetVar() - Bad varname with []: " << vn << endl; return false; } string vna = vn.substr(0, p); string sia = vn.substr(p+1, q-(p+1)); if (isalpha(sia[0])) { string sia2; if (!Var2Str(sia, sia2) || (sia2.length() < 1)) { cerr << "Commander::Str2Var/SetVar() Syntax error- varname[index]:" << vn << endl; return false; } sia = sia2; } int iarr; int rcdia = ctoi(sia.c_str(), &iarr); if (rcdia < 0) { cerr << "Commander::Str2Var/SetVar() Syntax error- varname[iarr]: " << vn << endl; return false; } return SetVar(vna, iarr, vv); } else { if (vn == "status") { _xstatus = atoi(vv.c_str()); return true; } else if (vn == "retstr") { _retstr = vv; return true; } else return SetVar(vn, vv); } } /* --Methode-- */ bool Commander::GetVar(string const & vn, string & vv) { CmdVarList::iterator it = variables.find(vn); if (it == variables.end()) { vv = ""; return false; } vv = (*it).second[0]; if ((*it).second.size() > 1) { for(int k=1; k<(*it).second.size(); k++) { vv += ' '; vv += (*it).second[k]; } } return true; } /* --Methode-- */ bool Commander::GetVar(string const & vn, int idx, string & vv) { vv = ""; CmdVarList::iterator it = variables.find(vn); if (it == variables.end()) return false; if ((idx < 0) || (idx > (*it).second.size()-1)) return false; vv = (*it).second[idx]; return true; } /* --Methode-- */ bool Commander::GetVar(string const & vn, vector & vv) { vv.clear(); // vv.erase(vv.begin(),vv.end()); CmdVarList::iterator it = variables.find(vn); if (it == variables.end()) return false; vv = (*it).second; return true; } /* --Methode-- */ bool Commander::SetVar(string const & vn, string const & val) { if ( !CheckVarName(vn) ) { cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl; return(false); } bool fg = false; vector nouv; nouv.push_back(val); CmdVarList::iterator it = variables.find(vn); if (it == variables.end()) variables[vn] = nouv; else { (*it).second = nouv; fg = true; } return fg; } /* --Methode-- */ bool Commander::SetVar(string const & vn, int idx, string const & val) { if ( !CheckVarName(vn) ) { cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl; return(false); } if ((vn == "status") || (vn == "retstr")) { cerr << "Commander::SetVar(vn,idx,val) ERROR - special var status/retstr " << endl; return(false); } if (idx < 0) { cout << "Commander::SetVar(vn," << idx << ",...) Error idx < 0" << endl; return(false); } bool fg = false; CmdVarList::iterator it = variables.find(vn); if (it == variables.end()) { vector nouv; for(int j=0; j= (*it).second.size()) for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back(""); (*it).second[idx] = val; fg = true; } return fg; } /* --Methode-- */ bool Commander::SetVar(string const & vn, vector const & val) { if ( !CheckVarName(vn) ) { cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl; return(false); } if ((vn == "status") || (vn == "retstr")) { cerr << "Commander::SetVar(vn, vector) ERROR - special var status/retstr " << endl; return(false); } bool fg = false; CmdVarList::iterator it = variables.find(vn); if (it == variables.end()) variables[vn] = val; else { (*it).second = val; fg = true; } return fg; } /* --Methode-- */ bool Commander::CheckVarName(string const & vn) { size_t l,k; l = vn.length(); if (l < 1) return false; if (!isalpha(vn[0])) return false; for(k=1; k Size= " << vs << endl; } cout << "---------------------------------------------------------- " << endl; } /* --Methode-- */ bool Commander::GetVarApp(string const & vn, string & vv) { vv = ""; // cout << " Commander::GetVarApp() Not available ! " << endl; return false; } /* --Methode-- */ bool Commander::SetVarApp(string const & vn, string const & vv) { // cout << " Commander::SetVarApp() Not available ! " << endl; return false; } /* --Methode-- */ bool Commander::DeleteVarApp(string const & vn) { // cout << " Commander::DeleteVarApp() Not available ! " << endl; return false; } /* --Methode-- */ void Commander::ListVarApp() { // cout << " Commander::ListVarApp() Not available ! " << endl; return; } /* --Methode-- */ bool Commander::GetVarEnv(string const & vn, string & vv) { char* vev = getenv(vn.c_str()); if (vev) { vv = vev; return true; } else { vv = ""; return false; } } /* --Methode-- */ bool Commander::SetVarEnv(string const & vn, string const & vv) { string pev = vn; pev += '='; pev += vv; #if defined(Linux) // Reza - 28/04/2004 // putenv de Linux ne declare pas la variable char *string const // On ne doit meme pas utiliser une variable automatique // J'alloue donc un nouveau tableau - mais qui va le liberer ? char* bev = new char[pev.size()+1]; strcpy(bev, pev.c_str()); if (putenv(bev) == 0) return true; #else if (putenv(pev.c_str()) == 0) return true; #endif else return false; } /* --Methode-- */ bool Commander::DeleteVarEnv(string const & vn) { // cout << " Commander::DeleteVarEnv() Not available ! " << endl; return false; } /* --Methode-- */ void Commander::ListVarEnv() { cout << " Commander::ListVarEnv() Not available ! " << endl; return; } /* --Methode-- */ string Commander::GetTmpDir() { return("/tmp"); } /* --Methode-- */ void Commander::SetCurrentPrompt(const char* pr) { curprompt = pr; } /* --Methode-- */ void Commander::ShowMessage(const char * msg, int att) { cout << msg ; } /* --Methode-- */ int Commander::EvaluateTest(vector & args, string & line, bool & res) { res = true; if ((args.size() != 6) || (args[5] != "then") || (args[0] != "(") || (args[4] != ")") ) return(1); if (args[2] == "==") res = (args[1] == args[3]); else if (args[2] == "!=") res = (args[1] != args[3]); else if (args[2] == "<") res = (atof(args[1].c_str()) < atof(args[3].c_str())); else if (args[2] == ">") res = (atof(args[1].c_str()) > atof(args[3].c_str())); else if (args[2] == "<=") res = (atof(args[1].c_str()) <= atof(args[3].c_str())); else if (args[2] == ">=") res = (atof(args[1].c_str()) >= atof(args[3].c_str())); else return(2); return(0); } /* --Methode-- */ int Commander::EvalRPNExpr(vector & args, string & line) { // A virer - Reza 15/03/2004 return(0); } /* --Methode-- */ void Commander::PushStack(vector& args) { // We push the argument list (args) on the stack ArgsStack.push(args); // We push also CommanderBloc and testresult on the stack CmdBlks.push(NULL); list xtx; TestsStack.push(xtx); } /* --Methode-- */ void Commander::PopStack(bool psta) { // We remove the argument list (args) from the stack if (psta) ArgsStack.pop(); // And CommanderBloc and TestResult from the corresponding stacks CommanderBloc* curb = CmdBlks.top(); while (curb != NULL) { CommanderBloc* parb = curb->Parent(); delete curb; curb = parb; } CmdBlks.pop(); TestsStack.pop(); } /* --Methode-- */ int Commander::ExecuteCommandLine(string & kw, vector & tokens, string & toks) { int rc = 0; // >>>>>>>>>>> Commande d'interpreteur if (kw == "help") { if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl; else { string kwh = "Commander"; cout << GetUsage(kwh) << endl; } } else if (kw == "sleep") { if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: sleep nsec " << endl; return(1); } int nsec = atoi(tokens[0].c_str()); cout << "Commander::Interpret() sleep " << nsec << " seconds" << endl; sleep(nsec); } else if (kw == "set") { if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl; return(1); } if (tokens.size() == 2) SetVariable(tokens[0], tokens[1]); else { if ( (tokens[1] != "(") || (tokens[tokens.size()-1] != ")") ) { cout << "Commander::Interpret() Usage: set vecvar ( w1 w2 ... ) " << endl; return(1); } string vname = tokens[0]; vector::iterator vit; vit = tokens.begin(); tokens.erase(vit); vit = tokens.begin(); tokens.erase(vit); tokens.pop_back(); SetVar(vname, tokens); } return 0; } else if (kw == "var2words") { if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl; return(1); } char sep = ' '; if (tokens.size() > 2) sep = tokens[2][0]; string vv; if (!GetVar(tokens[0], vv)) { cout << "Commander::Interpret() var2words/Error No variable with name " << tokens[0] << endl; return 2; } vector vs; FillVStringFrString(vv, vs, sep); SetVar(tokens[1], vs); } else if (kw == "alias") { if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: alias aliasname string" << endl; return(0); } if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) { cerr << "Commander::Interpret()/Error alias name should start with alphabetic" << endl; return(1); } string xx = tokens[1]; for (int kk=2; kk>> Reading From StdIn \n", _MAGENTA_); cout << tokens[0] << " ? " << endl; SetVar(tokens[0], GetStringFrStdin(this) ); } else if (kw == "listvar") ListVar(); else if (kw == "listalias") { cout << "Commander::Interpret() Alias List , AliasName = Value \n"; CmdStrList::iterator it; for(it = mAliases.begin(); it != mAliases.end(); it++) cout << (*it).first << " = " << (*it).second << "\n"; cout << endl; } else if (kw == "listcommands") { cout << "---- Commander::Interpret() Command List ----- \n"; CmdExmap::iterator it; int kc = 0; for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) { cout << (*it).first << " "; kc++; if (kc >= 5) { cout << "\n"; kc = 0; } } cout << endl; } else if (kw == "listscripts") { cout << "---- Commander::Interpret() Script List ----- \n"; for(ScriptList::iterator sit = mScripts.begin(); sit != mScripts.end(); sit++) cout << " Script: " << (*sit).second->Name() << " - " << (*sit).second->Comment() << endl; } else if (kw == "clearscript") { if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: clearscript scriptname" << endl; return(0); } ScriptList::iterator sit = mScripts.find(tokens[0]); if (sit == mScripts.end()) { cout << "Commander::Interpret() No script with name" << tokens[0] << endl; return(0); } else { delete (*sit).second; mScripts.erase(sit); cout << "Commander::Interpret() script " << tokens[0] << " cleared" << endl; return(0); } } else if (kw == "traceon") { cout << "Commander::Interpret() -> Trace ON mode " << endl; trace = true; } else if (kw == "traceoff") { cout << "Commander::Interpret() -> Trace OFF mode " << endl; trace = false; } else if (kw == "timingon") { cout << "Commander::Interpret() -> Timing ON mode " << endl; if (gltimer) delete gltimer; gltimer = new Timer("PIA-CmdInterpreter "); timing = true; } else if (kw == "timingoff") { cout << "Commander::Interpret() -> Timing OFF mode " << endl; if (gltimer) delete gltimer; gltimer = NULL; timing = false; } else if (kw == "exec") { if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: exec filename" << endl; return(0); } ExecFile(tokens[0], tokens); } else if (kw == "autoiniranf") { Auto_Ini_Ranf(1); return(0); } else if (kw == "shell") { if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: shell cmdline" << endl; return(0); } string cmd; for (int ii=0; iiSplit(); return(rc); } /* --Methode-- */ int Commander::ParseLineExecute(string& line, bool qw) // Si qw == true, on decoupe entre '' ou "" ou espaces { vector tokens; vector qottoks; string kw, toks; if (line.length() < 1) return(0); LineToWords(line, kw, tokens, qottoks, toks, qw); return(ExecuteCommand(kw, tokens, toks)); } /* --Methode-- */ int Commander::ExecuteCommand(string& keyw, vector& args, string& toks) { int rc = -1; CmdExmap::iterator it = cmdexmap.find(keyw); if (it == cmdexmap.end()) cout << "No such command : " << keyw << " ! " << endl; else { if ((*it).second.cex) rc = (*it).second.cex->Execute(keyw, args, toks); else cout << "Dont know how to execute " << keyw << " ? " << endl; } return(rc); } /* --Methode-- */ int Commander::ExecFile(string& file, vector& args) { char line_buff[512]; FILE *fip; int rcc = 0; if ( (fip = fopen(file.c_str(),"r")) == NULL ) { if (file.find('.') >= file.length()) { cout << "Commander::Exec(): Error opening file " << file << endl; file += ".pic"; cout << " Trying file " << file << endl; fip = fopen(file.c_str(),"r"); } } if(fip == NULL) { cerr << "Commander::Exec() Error opening file " << file << endl; hist << "##! Commander::Exec() Error opening file " << file << endl; return(0); } // hist << "### Executing commands from " << file << endl; PushStack(args); if (trace) { ShowMessage("### Executing commands from ", _MAGENTA_); ShowMessage(file.c_str(), _MAGENTA_); ShowMessage("\n", _MAGENTA_); } bool ohv = histon; histon = false; while (fgets(line_buff,511,fip) != NULL) { if (trace) ShowMessage(line_buff, _MAGENTA_); line_buff[strlen(line_buff)-1] = '\0'; /* LF/CR de la fin */ string line(line_buff); rcc = Interpret(line); if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break; } histon = ohv; // hist << "### End of Exec( " << file << " ) " << endl; if (trace) { ShowMessage("### End of Exec( ", _MAGENTA_); ShowMessage(file.c_str(), _MAGENTA_); ShowMessage(" ) \n", _MAGENTA_); } PopStack(true); return(0); } /* --Methode-- */ int Commander::CShellExecute(string cmd) { if(cmd.size()<=0) return -1; string fname = GetTmpDir(); fname += "cshell_exec_pia.csh"; string cmdrm = "rm -f " + fname; system(cmdrm.c_str()); FILE *fip = fopen(fname.c_str(),"w"); if(fip==NULL) { cout << "Commander/CShellExecute_Error: fopen("< 0) fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str()); fprintf(fip,"\\noindent \n"); for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) { if ((*ite).second.group != gid) continue; prl = (*ite).first; check_latex_reflabel(prl); mol = check_latex_underscore((*ite).first); fprintf(fip,"\\piahelpitem{%s} \\label{%s} \n", mol.c_str(), prl.c_str()); fputs("\\begin{verbatim} \n",fip); fprintf(fip,"%s\n", (*ite).second.us.c_str()); fputs("\\end{verbatim} \n",fip); } for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) { if ((*ite).second.group != gid) continue; prl = (*ite).first; check_latex_reflabel(prl); mol = check_latex_underscore((*ite).first); fprintf(fip,"\\piacommand{%s} \\label{%s} \n", mol.c_str(), prl.c_str()); fputs("\\begin{verbatim} \n",fip); fprintf(fip,"%s\n", (*ite).second.us.c_str()); fputs("\\end{verbatim} \n",fip); } } fclose(fip); cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl; return; } } // End of namespace SOPHYA