Index: /trunk/SophyaLib/SysTools/Makefile
===================================================================
--- /trunk/SophyaLib/SysTools/Makefile	(revision 2445)
+++ /trunk/SophyaLib/SysTools/Makefile	(revision 2446)
@@ -3,7 +3,7 @@
 all: $(LIB)libSysTools.a
 clean:
-	rm -f $(OBJ)ctimer.o $(OBJ)cxxcmplnk.o $(OBJ)pdlmgr.o $(OBJ)periodic.o $(OBJ)psighand.o $(OBJ)resusage.o $(OBJ)zthread.o $(OBJ)timing.o
+	rm -f $(OBJ)commander.o $(OBJ)ctimer.o $(OBJ)cxxcmplnk.o $(OBJ)pdlmgr.o $(OBJ)periodic.o $(OBJ)psighand.o $(OBJ)resusage.o $(OBJ)zthread.o $(OBJ)timing.o
 	rm -f $(LIB)libSysTools.a
-$(LIB)libSysTools.a : $(OBJ)ctimer.o $(OBJ)cxxcmplnk.o $(OBJ)pdlmgr.o $(OBJ)periodic.o $(OBJ)psighand.o $(OBJ)resusage.o $(OBJ)timing.o $(OBJ)zthread.o
+$(LIB)libSysTools.a : $(OBJ)commander.o $(OBJ)ctimer.o $(OBJ)cxxcmplnk.o $(OBJ)pdlmgr.o $(OBJ)periodic.o $(OBJ)psighand.o $(OBJ)resusage.o $(OBJ)timing.o $(OBJ)zthread.o
 	$(ARCXX) $(ARCXXFLAGS) $@ $($(ARARGS))
 ifeq ($(CXX),cxx)
@@ -11,4 +11,9 @@
 endif 
  
+$(OBJ)commander.o: commander.cc commander.h \
+ $(INC)machdefs.h pdlmgr.h ctimer.h \
+ $(INC)strutil.h \
+ $(INC)strutilxx.h \
+ $(INC)srandgen.h
 $(OBJ)ctimer.o: ctimer.cc $(INC)machdefs.h ctimer.h
 $(OBJ)cxxcmplnk.o: cxxcmplnk.cc cxxcmplnk.h \
Index: /trunk/SophyaLib/SysTools/commander.cc
===================================================================
--- /trunk/SophyaLib/SysTools/commander.cc	(revision 2446)
+++ /trunk/SophyaLib/SysTools/commander.cc	(revision 2446)
@@ -0,0 +1,1877 @@
+#include "commander.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "strutil.h"
+#include "strutilxx.h"
+#include "srandgen.h"
+
+
+// ------------------------------------------------------------
+//         Bloc de commandes (Foreach, ...)    
+//               Classe  CommanderBloc    
+// ------------------------------------------------------------
+/*!
+  \class SOPHYA::CommanderBloc
+  \ingroup SysTools 
+  Class for internal use by SOPHYA::Commander to handle loops
+*/
+class CommanderBloc {
+public:
+  enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat };
+
+  CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& 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()); }
+  CommanderBloc*	Execute();
+  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;
+  vector<string> strlist;
+  vector<string> lines;
+  vector<CommanderBloc *> blocs;
+  vector<int> 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<string>& 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"))  return;
+varname = args[0];  // $CHECK$ Variable name should be checked 
+//if (isalpha((int)args[1][0]) ) {  This is a foreach bloc with string list
+if (kw == "foreach" ) { // This is a foreach bloc with string list
+  if ((args[1] != "(") || (args[args.size()-1] != ")") ) return;
+  for(int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
+  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; k<blocs.size(); k++) delete blocs[k];
+}
+
+/* --Methode-- */
+void CommanderBloc::AddLine(string& line, string& kw)
+{
+  AddLine(line);
+  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; 
+}
+
+/* --Methode-- */
+CommanderBloc* CommanderBloc::Execute()
+{
+// cout << " DBG * CommanderBloc::Execute() " << typ << " - " << bloclineid.size() <<
+//      " I1,I2=" << i1 << " , " << i2 << " , " << di << endl;
+string cmd;
+int k=0;
+int kj=0;
+int kk=0;
+char buff[32];
+int rcc = 0;
+
+int mxloop = _commander->GetMaxLoopLimit();
+
+if (typ == BT_ForeachList)   // foreach string loop
+  for(k=0; k<strlist.size(); k++) {
+    cmd = "set " + varname + " '" + strlist[k] + "'";
+    _commander->Interpret(cmd);
+    for(kj=0; kj<bloclineid.size(); kj++) {
+      kk = bloclineid[kj]; 
+      if (kk > 0)  { 
+	rcc = _commander->Interpret(lines[kk-1]);
+	if (rcc == 77766)  break;
+      }
+      else blocs[-kk-1]->Execute();
+    }
+    if (rcc == 77766)  break;
+  }
+else if (typ == BT_ForeachInt)  // Integer loop
+  for(int i=i1; i<i2; i+=di) {
+    k++;
+    if ((mxloop>0) && (k > mxloop)) {
+      cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
+      break;
+      }
+    sprintf(buff, " %d", i);
+    cmd = "set " + varname + buff;
+    _commander->Interpret(cmd);
+    for(kj=0; kj<bloclineid.size(); kj++) {
+      kk = bloclineid[kj]; 
+      if (kk > 0)  { 
+	rcc = _commander->Interpret(lines[kk-1]);
+	if (rcc == 77766)  break;
+      }
+      else blocs[-kk-1]->Execute();
+    }
+    if (rcc == 77766)  break;
+  }
+else if (typ == BT_ForeachFloat)  // float loop
+  for(float f=f1; f<f2; f+=df) {
+    k++;
+    if ((mxloop>0) && (k > mxloop)) {
+      cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
+      break;
+      }
+    sprintf(buff, " %g", f);
+    cmd = "set " + varname + buff;
+    _commander->Interpret(cmd);
+    for(kj=0; kj<bloclineid.size(); kj++) {
+      kk = bloclineid[kj]; 
+      if (kk > 0)  { 
+	rcc = _commander->Interpret(lines[kk-1]);
+	if (rcc == 77766)  break;
+      }
+      else blocs[-kk-1]->Execute();
+    }
+    if (rcc == 77766)  break;
+  }
+
+return(parent); 
+}
+
+// ---------------------------------------------------------------
+//                  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. 
+// ---------------------------------------------------------------
+
+/*!
+  \class SOPHYA::CommanderScript
+  \ingroup SysTools 
+  Class for internal use by SOPHYA::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<string>& 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<string> 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<string>& args)
+{
+  if (!CheckScript()) return(-1);
+  cout << " CommanderScript::Execute() - Executing script " << Name() << endl;
+  for(int k=0; k<lines.size(); k++) {
+    if (_commander->Interpret(lines[k]) == 77777) break;
+  }
+  return(0);
+}
+
+// ------------------------------------------------------------
+//         Classe Commander
+// ------------------------------------------------------------
+typedef void (* DlModuleInitEndFunction) ();
+
+/*!
+  \class SOPHYA::Commander
+  \ingroup SysTools
+  Simple command interpreter with c-shell like syntax and dynamic 
+  load capabilities. Can be used to add scripting capabilities
+  to applications
+*/
+
+#define _MAGENTA_ 1
+
+static Commander* cur_commander = NULL;
+/* --Methode-- */
+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);
+curscript = NULL;
+
+CmdBlks.push(NULL);
+list<char> xtx;
+TestsStack.push(xtx);
+curtestresult = true;
+
+// cmdhgrp["All"] = 0;
+
+string kw = "Commander";
+string usage;
+usage = ">>> (Commander) Interpreter's keywords : \n";
+usage += "  > set varname string   # To set a variable, $varname \n";
+usage += "  > get newvarname varname # To set a newvariable, equal to $varname \n";
+usage += "  > setol varname patt     # Fills varname with object list \n";
+usage += "  > unset varname          # clear variable definition \n";
+usage += "  > rpneval varname RPNExpression # Reverse Polish Notation evaluation \n";
+usage += "  > varname = 'string string ...' # To set a variable, $varname  \n";
+usage += "  > varname = RPNExpression # RPN evaluation / result -> varname \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 += "  > readstdin varname      # reads a line from stdin into $varname \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 += "  > 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 <command_name>  # <command_name> usage info \n"; 
+usage += "  > helpwindow           # Displays help window \n";
+usage += "  > timingon  timingoff traceon  traceoff \n";
+string grp = "Commander";
+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-- */
+string Commander::Name()
+{
+return("Commander");
+}
+
+/* --Methode-- */
+void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string grp)
+{
+if (!ce) { 
+  RegisterHelp(keyw, usage, grp);
+  return;
+  }
+int gid = CheckHelpGrp(grp);
+cmdex cme;
+cme.group = gid;
+cme.us = usage;
+cme.cex = ce;
+cmdexmap[keyw] = cme;
+}
+
+/* --Methode-- */
+void Commander::RegisterHelp(string& keyw, string& usage, string& grp)
+{
+int gid = CheckHelpGrp(grp);
+cmdex cme;
+cme.group = gid;
+cme.us = usage;
+cme.cex = NULL;
+helpexmap[keyw] = cme;
+}
+
+/* --Methode-- */
+int Commander::CheckHelpGrp(string& grp)
+{
+int gid=0;
+CmdHGroup::iterator it = cmdhgrp.find(grp);
+if (it == cmdhgrp.end()) {
+  cmdgrpid++;   gid = cmdgrpid;
+  cmdhgrp[grp] = gid;
+  //  _helpmgr->AddHelpGroup(grp.c_str(), gid);
+  }
+else gid = (*it).second;
+return(gid);
+}
+
+
+/* --Methode-- */
+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-- */
+void Commander::AddInterpreter(CmdInterpreter * cl)
+{
+if (!cl) return;
+interpmap[cl->Name()] = cl;}
+
+/* --Methode-- */
+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-- */
+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;
+    return(1);
+  }
+}
+
+// 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;
+      return(0);
+    }
+    else {
+      cout << "Commander::Interpret() Error in Script " << curscript->Name() 
+	   << " definition " << endl;
+      SetCurrentPrompt("Cmd> ");
+      curscript = NULL;
+      return(2);
+    }
+  }
+  else curscript->AddLine(s, kw);
+  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;
+      return(2);  
+    }
+       //       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<char> xtx;
+      TestsStack.push(xtx);
+      curb->Execute();
+      // And CommanderBloc and TestResult from the corresponding stacks
+      PopStack(false);
+    }
+    delete curb;
+    histon = ohv;
+  }
+  else CmdBlks.top()->AddLine(s, kw); 
+  return(0);
+}
+else if (kw == "end") {
+  cerr << "Commander::Interpret()/syntax error - end outside for/foreach bloc \n"
+       << "line: " << s << endl;
+  return(1);  
+}
+
+// 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;
+      return(1);
+    }
+    else { 
+      const char * npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
+      if ((*tresit)&1)  curtestresult = false;
+      SetCurrentPrompt(npr);
+      (*tresit) |= 2;
+      return(0);
+    }
+  }
+  else if (kw == "endif") {
+    list<char>::iterator dbit = tresit;
+    tresit--;
+    TestsStack.top().erase(dbit);
+    const char * npr = "Cmd> ";
+    if (TestsStack.top().size() > 1) {
+      curtestresult = true;
+      list<char>::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);
+    return(0);
+  }
+} 
+else if ((kw == "else") || (kw == "endif")) {
+  cerr << "Commander::Interpret()/syntax error - else,endif outside if bloc \n"
+       << "line: " << s << endl;
+  return(1);  
+}
+
+bool fgcont = true;
+if (TestsStack.top().size() > 0) { // Resultat de if ou else
+  list<char>::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"))  return(0);
+
+
+// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
+if (kw == "break") return(77766);
+else if (kw == "return")  return(77777);
+
+// 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;
+  return(rcs);
+}
+// >>>> Separating keyword and tokens 
+vector<string> tokens;
+/* decoupage en mots */
+LineToWords(s2, kw, tokens, toks, true);
+
+// Si c'est un for/foreach, on cree un nouveau bloc
+if ((kw == "foreach") || (kw == "for")) {
+  //     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;
+    return(1);
+    }
+  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;
+    return(1);
+  }
+  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 = RPNExpression (Evaluation d'expression RPN)
+  tokens[0] = kw;
+  int rcev = EvalRPNExpr(tokens, s);
+  if (rcev) {
+    cerr << "Commander::Interpret() evaluation (RPN) syntax Error ! " << "line: " << s << endl;
+    return(1);
+  }
+  return(0);
+}
+else if (kw == "defscript") {  // definition de script
+  if (tokens.size() > 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;
+    return(1);
+  }
+}
+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);
+  return(rc);
+}  
+// cout << "Commander::Do() DBG  KeyW= " << kw << " NbArgs= " << tokens.size() << endl;
+//  for(int ii=0; ii<tokens.size(); ii++)
+//  cout << "arg[ " << ii << " ] : " << tokens[ii] << endl;
+
+return(0);
+}
+
+
+/* --Methode-- */
+int Commander::LineToWords(string& line, string& kw, vector<string>& tokens, 
+			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)  {
+  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++;
+  }
+  else {
+    q = toks.find_first_of(" \t",p); // la fin du token;
+  }
+  string token = toks.substr(p,q-p);
+  tokens.push_back(token);  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 (!GetVar(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 (!GetVar(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 (!GetVar(vn, vv)) return(5);
+  if (iarr < 0) {
+    s2 += (s.substr(p, q-p) + vv);
+    p = q2;
+  }
+  else {
+    vector<string> vs;
+    FillVStringFrString(vv, vs);
+    if (iarr >= vs.size()) {
+      cerr << " Substitution error - word index out of range in "
+	   << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
+      return(4);
+    }
+    else s2 += (s.substr(p, q-p) + vs[iarr]);
+    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::GetVar(string & vn, string & vv)
+{
+if (vn.length() < 1) {
+  cerr << " Commander::SubstituteVar/Error: length(varname=" << vn << ")<1 !" << endl;
+  vv = "";    return(false);
+}
+// Variable de type $# $0 $1 ... (argument de .pic ou de script)
+int ka = 0;
+if (vn == "#") {
+  if (ArgsStack.empty()) {
+    cerr << " Commander::SubstituteVar/Error: ArgsStack empty ! " 
+	 << " ($" << vn << ")" << endl;
+    vv = "";  return(false);
+  }
+  char buff[32];
+  long an = ArgsStack.top().size();
+  sprintf(buff,"%ld", an);
+  vv = buff;  return(true);
+}
+else if (ctoi(vn.c_str(), &ka) > 0) {  // $0 $1 $2 ...
+  if (ArgsStack.empty()) {
+    cerr << " Commander::SubstituteVar/Error: ArgsStack empty ! " 
+	 << " ($" << vn << ")" << endl;
+    vv = ""; return(false);
+  }
+  if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) {
+    cerr << " Commander::SubstituteVar/Error: Undefined variable ! " 
+	 << " ($" << vn << ")" << endl;
+    vv = ""; return(false);
+  }
+  vv = ArgsStack.top()[ka];  return(true);
+}
+else if (vn[0] == '#') {  // Variable de type $#vname --> size(vname) 
+  vn = vn.substr(1);
+  if (!HasVariable(vn) ) {
+    cerr << " Commander::SubstituteVarError: Undefined variable " 
+	 << vn << " ! " << endl;
+    vv = "";  return(false);
+  }
+  vn = GetVariable(vn);
+  vector<string> vs;
+  FillVStringFrString(vn, vs);
+  char buff[32];
+  sprintf(buff,"%d", (int)vs.size());
+  vv = buff; return(true);
+  } 
+else {  // variable ordinaire geree par NamedObjMgr
+  if ( (!HasVariable(vn)) )  {
+    cerr << " Commander::SubstituteVarError: Undefined variable " 
+	 << vn << " ! " << endl;
+    vv = "";  return(false);
+  }
+  vv = GetVariable(vn);  return(true);
+}
+
+return(false);
+}
+/* --Methode-- */
+string Commander::GetVariable(string const & key)
+{
+  if ((key.length() < 1) || (! isalpha(key[0])) )   {
+    cout << "Commander::GetVariable( " << key << ") Bad VarName " << endl;
+    return("");
+  }
+  // cout << " DEBUG::GetVar " << variables << endl;
+  return(variables.GetS(key));
+}
+
+/* --Methode-- */
+bool Commander::HasVariable(string const & key)
+{
+  if ((key.length() < 1) || (! isalpha(key[0])) )   {
+    cout << "Commander::HasVar( " << key << ") Bad VarName " << endl;
+    return(false);
+  }
+  return(variables.HasKey(key));
+}
+
+/* --Methode-- */
+bool Commander::SetVar(string const & key, string const & val)
+{
+   if ((key.length() < 1) || (! isalpha(key[0])) )   {
+    cout << "Commander::SetVar( " << key << " ...) Bad VarName " << endl;
+    return(false);
+  }
+  bool fg = variables.HasKey(key);
+  variables.SetS(key, val);
+  // cout << " DEBUG::SetVar " << variables << endl;
+  return fg;
+}
+
+/* --Methode-- */
+bool Commander::DeleteVar(string const & key)
+{
+  if ((key.length() < 1) || (! isalpha(key[0])) )   {
+    cout << "Commander::DeleteVar( " << key << ") Bad VarName " << endl;
+    return(false);
+  }
+  return(variables.DeleteKey(key));
+}
+
+/* --Methode-- */
+void Commander::ListVars()
+{
+  cout << " ---- Commander::ListVars() List of defined variables ---- " 
+       << endl;
+  cout << variables;
+  cout << "---------------------------------------------------------- " 
+       << endl;
+}
+
+/* --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<string> & 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);
+}
+
+/* Operations sur le stack RPN */
+inline bool Check_myRPNStack_(stack<double>& s, double& x, string& line) 
+{
+  if (s.empty()) { 
+    cerr << "Commander::EvalRPNExpr: syntax error / empty RPN stack " << line << endl; 
+    return true; 
+  } 
+  else x = s.top();
+  return false;
+}
+inline bool Check_myRPNStack_(stack<double>& s, double& x, double& y, string& line) 
+{
+  if (s.size() < 2) { 
+    cerr << "Commander::EvalRPNExpr: syntax error / RPN stack size < 2  " << line << endl; 
+    return true; 
+  }  
+ else { 
+   x = s.top(); s.pop(); y = s.top(); 
+ }
+  return false;
+}
+
+inline void Print_myRPNStack_(stack<double> s)
+{
+  if (s.empty()) 
+    cout << "Commander::EvalRPNExpr/PrintStack: Empty stack " << endl;
+  else {
+    int k = 0;
+    cout << "Commander::EvalRPNExpr/PrintStack: Size()= " << s.size() << endl;
+    while( !s.empty() ) {
+      cout << "    " << k << ":  " << s.top() << "  ";
+      if (k == 0)  cout << " (x) " << endl;
+      else if (k == 1) cout << " (y) " << endl;
+      else if (k == 2) cout << " (z) " << endl;
+      else cout << endl;
+      s.pop(); k++;
+    }
+  }
+  
+} 
+
+int Sum_RPNStack_(stack<double>& s, double& sx, double& sx2, string& line) 
+{
+  sx = sx2 = 0.;
+  int nn = 0;
+  double x = 0.;
+  while( !s.empty() ) {
+    x = s.top(); s.pop();
+    sx += x; sx2 += x*x;
+    nn++;
+  } 
+  return(nn);  
+}
+
+int Product_RPNStack_(stack<double>& s, double& px, string& line) 
+{
+  px = 1.;
+  int nn = 0;
+  double x = 0.;
+  while( !s.empty() ) {
+    x = s.top(); s.pop();
+    px *= x;  nn++;
+  } 
+  return(nn);  
+}
+  
+/* --Methode-- */
+int Commander::EvalRPNExpr(vector<string> & args, string & line)
+{
+  
+  if (args.size() < 2) { 
+    cerr << "Commander::EvalRPNExpr: syntax error / missing arguments " << line << endl; 
+    return(1);
+  }
+  else if (args.size() == 2) { 
+    SetVar(args[0], args[1]);
+    return(0); 
+  }
+
+  double x,y;
+  x = y = 0.;
+  stack<double> rpnstack;  // Stack des operations en RPN 
+  for(int k=1; k<args.size(); k++) {
+    // Les 4 operations de base + - * / 
+    if (args[k] == "+") { 
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = y+x;
+    }
+    else if (args[k] == "-") { 
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = y-x;
+    }
+    else if (args[k] == "*") { 
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = y*x;
+    }
+    else if (args[k] == "/") { 
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = y/x;
+    }
+    else if (args[k] == "%") { 
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = (int)y % (int)x;
+    }
+    // Les constantes : e , pi
+    else if (args[k] == "e") {
+      rpnstack.push(M_E);
+    }
+    else if (args[k] == "pi") {
+      rpnstack.push(M_PI);
+    }
+    // Les fonctions usuelles a 1 argument f(x)
+    else if (args[k] == "cos") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = cos(x);
+    }
+    else if (args[k] == "sin") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = sin(x);
+    }
+    else if (args[k] == "tan") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = tan(x);
+    }
+    else if (args[k] == "acos") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = acos(x);
+    }
+    else if (args[k] == "asin") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = asin(x);
+    }
+    else if (args[k] == "atan") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = atan(x);
+    }
+    else if (args[k] == "chs") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = -x;
+    }
+    else if (args[k] == "sqrt") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = sqrt(x);
+    }
+    else if (args[k] == "sq") {  // x^2 
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = x*x;
+    }
+    else if (args[k] == "log") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = log(x);
+    }
+    else if (args[k] == "log10") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = log10(x);
+    }
+    else if (args[k] == "exp") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = exp(x);
+    }
+    else if (args[k] == "fabs") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = fabs(x);
+    }
+    else if (args[k] == "floor") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = floor(x);
+    }
+    else if (args[k] == "ceil") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = ceil(x);
+    }
+    // trunc et nint vire - ca ne compile pas sous linux - Reza 01/2003
+    else if (args[k] == "deg2rad") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = x*M_PI/180.;
+    }
+    else if (args[k] == "rad2deg") {
+      if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+      rpnstack.top() = x*180./M_PI;
+    }
+    // Les fonctions usuelles a 2 argument f(x,y)
+    else if (args[k] == "pow") { 
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = pow(y,x);
+    }
+    else if (args[k] == "atan2") { 
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = atan2(x,y);
+    }
+    // generateur aleatoire
+    else if (args[k] == "rand") { 
+      double rnd = drand01();
+      rpnstack.push(rnd);
+    }
+    else if (args[k] == "norand") { 
+      double rnd = GauRnd(0., 1.);
+      rpnstack.push(rnd);
+    }
+    // Fonction a N arguments  - Somme, produit, etc ...
+    else if ((args[k] == "sum") || (args[k] == "mean") || (args[k] == "sigmean") || 
+	     (args[k] == "sigma") || (args[k] == "sigma2") ) {
+      double sx, sx2;
+      int nn = Sum_RPNStack_(rpnstack, sx, sx2, line);
+      if (args[k] == "sum") rpnstack.push(sx);
+      else { 
+	if (nn == 0) {
+	  cerr << "Commander::EvalRPNExpr: mean/sigma error- RPN stack empty: " 
+	       << line << endl; 
+	  return(1);
+	}
+	double fnn = nn;
+	if ((args[k] == "sigma") || (args[k] == "sigmean")) 
+	  rpnstack.push(sqrt(sx2/fnn-(x*x/(fnn*fnn))));
+	else if ((args[k] == "mean") || (args[k] == "sigmean"))  rpnstack.push(sx/fnn);
+	else rpnstack.push(sx2/fnn-(x*x/(fnn*fnn)));
+      }
+    }
+    else if (args[k] == "product") { 
+      double px;
+      int nn = Product_RPNStack_(rpnstack, px, line);
+      if (nn == 0) {
+	cerr << "Commander::EvalRPNExpr: product error- RPN stack empty: " 
+	     << line << endl; 
+	return(1);
+      }
+      rpnstack.push(px);
+    }
+    // Fonctions de manipulation de stack
+    else if (args[k] == "print") { 
+      Print_myRPNStack_(rpnstack);
+    }
+    else if (args[k] == "x<>y") {
+      if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
+      rpnstack.top() = x;  rpnstack.push(y);
+    }
+    else if (args[k] == "pop") {
+      rpnstack.pop();
+    }
+    else if (args[k] == "push") {
+      if (rpnstack.empty()) rpnstack.push(0.);
+      else rpnstack.push(rpnstack.top());
+    }
+    // On met un nombre sur le stack 
+    else {
+      char * esptr;
+      x = strtod(args[k].c_str(), &esptr);
+      //      if (ctof(args[k].c_str(),&x) < 0) {
+      if (esptr == args[k].c_str()) {
+	cerr << "Commander::EvalRPNExpr: syntax error near " << args[k] 
+	     << " in expression: \n" << line << endl; 
+	return(2);
+      }
+      rpnstack.push(x);
+    }
+
+  }
+
+  if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
+  char buff[64];
+  sprintf(buff, "%g", x);
+  string res = buff;
+  SetVar(args[0], res);
+  return(0);
+}
+
+/* --Methode-- */
+void Commander::PushStack(vector<string>& 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<char> 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<string> & 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 == "set") {
+  if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: set varname string" << endl;  return(0); }
+  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
+    cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
+    return(0);
+    }
+  //  string xx = tokens[1];
+  //  for (int kk=2; kk<tokens.size(); kk++)  xx += (' ' + tokens[kk] );
+  SetVar(tokens[0], tokens[1]);
+  }
+
+else if (kw == "getvar") {
+  if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: getvar newvarname varname" << endl;  return(0); }
+  if (!HasVariable(tokens[1])) {
+    cerr << "Error - No " << tokens[1] << " Variable " << endl;
+    return(0);
+    } 
+  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
+    cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
+    return(0);
+    }
+  SetVar(tokens[0], GetVariable(tokens[1]) );
+  }
+
+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(0);
+    }
+  string xx = tokens[1];
+  for (int kk=2; kk<tokens.size(); kk++)  xx += (' ' + tokens[kk]);
+  mAliases[tokens[0]] = xx;
+  }
+
+else if (kw == "unset") {
+  if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: unset varname" << endl;  return(0); }
+  if (HasVariable(tokens[0])) DeleteVar(tokens[0]) ;
+  else cerr << "Commander::Interpret() No variable with name " << tokens[0] << endl;
+  }
+ else if (kw == "rpneval") {  // Evaluation d'expression en notation polonaise inverse
+  return(EvalRPNExpr(tokens, toks));
+}
+else if (kw == "echo") {
+  for (int ii=0; ii<tokens.size(); ii++)
+    cout << tokens[ii] << " " ;
+  cout << endl;
+ }
+else if (kw == "echo2file") {
+  if (tokens.size() < 1) {
+    cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;  
+    return(0);
+  }
+  ofstream ofs(tokens[0].c_str(), ios::app);
+  for (int ii=1; ii<tokens.size(); ii++)
+    ofs << tokens[ii] << " " ;
+  ofs << endl;
+ }
+else if (kw == "readstdin") {
+  if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: readstdin varname" << endl;  return(0); }
+  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
+    cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
+    return(0);
+    }
+  ShowMessage(">>> Reading From StdIn \n", _MAGENTA_);
+  cout << tokens[0] << " ? " << endl;
+  SetVar(tokens[0], GetStringFrStdin(this) );
+  }
+
+else if (kw == "listvars") ListVars();
+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; ii<tokens.size(); ii++)
+    cmd += (tokens[ii] + ' ');
+  system(cmd.c_str());
+  }
+else if (kw == "cshell") {
+  if(tokens.size()<1) {cout<<"Commander::Interpret() Usage: cshell cmdline"<<endl; return(0);}
+  string cmd="";
+  for(int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
+  CShellExecute(cmd);
+  }
+
+//  Execution d'une commande enregistree
+else rc = ExecuteCommand(kw, tokens, toks);
+
+if (timing)  gltimer->Split();
+return(rc);
+}
+
+/* --Methode-- */
+int Commander::ParseLineExecute(string& line, bool qw)
+  // Si qw == true, on decoupe entre '' ou "" ou espaces
+{
+vector<string> tokens;
+string kw, toks;
+if (line.length() < 1)  return(0);
+LineToWords(line, kw, tokens, toks, qw);
+return(ExecuteCommand(kw, tokens, toks));  
+}
+
+/* --Methode-- */
+int Commander::ExecuteCommand(string& keyw, vector<string>& 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<string>& args)
+{
+char line_buff[512];
+FILE *fip;
+
+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);
+  if (Interpret(line) == 77777) 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("<<fname<<") failed"<<endl; 
+   return -2; 
+ }
+ fprintf(fip,"#!/bin/csh\n\n");
+ fprintf(fip,"%s\n",cmd.c_str());
+ fprintf(fip,"\nexit 0\n");
+ fclose(fip);
+
+ cmd = "csh "; cmd += fname;
+ system(cmd.c_str());
+
+ system(cmdrm.c_str());
+
+ return 0;
+}
+
+static string* videstr = NULL;
+/* --Methode-- */
+string& Commander::GetUsage(const string& kw)
+{
+bool fndok = false;
+CmdExmap::iterator it = cmdexmap.find(kw);
+if (it == cmdexmap.end()) {
+  it = helpexmap.find(kw);
+  if (it != helpexmap.end())  fndok = true;
+  }
+  else  fndok = true; 
+if (fndok)   return( (*it).second.us ); 
+// Keyword pas trouve
+if (videstr == NULL) videstr = new string("");
+*videstr =  "Nothing known about " + kw + " ?? ";
+return(*videstr);
+ 
+}
+
+
+/*  Les definitions suivantes doivent se trouver ds l'en-tete du fichier LaTeX 
+  \newcommand{\piacommand}[1]{
+    \framebox{\bf \Large #1 } \index{#1} % (Command) 
+  }
+
+  \newcommand{\piahelpitem}[1]{
+    \framebox{\bf \Large #1 } \index{#1} (Help item)
+  }
+
+  \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
+*/
+
+// Fonction qui remplace tout caractere non alphanumerique en Z
+static void check_latex_reflabel(string & prl)
+{
+  for(int k=0; k<prl.length(); k++) 
+    if (! isalnum(prl[k]) )  prl[k] = 'Z';
+}
+// Fonction qui remplace _ en \_
+static string check_latex_underscore(string const & mot)
+{
+  string rs;
+  for(int k=0; k<mot.length(); k++) {
+    if (mot[k] == '_') rs += "\\_";
+    else rs += mot[k];
+  }
+  return rs;
+}
+
+/* --Methode-- */
+void Commander::HelptoLaTeX(string const & fname)
+{
+FILE *fip;
+if ((fip = fopen(fname.c_str(), "w")) == NULL)   { 
+  cout << "Commander::HelptoLaTex_Error: fopen( " << fname << endl; 
+  return;
+  }
+
+fputs("% ----- Liste des groupes de Help ----- \n",fip);
+fputs("List of {\\bf piapp} on-line Help groups: \n", fip);
+fputs("\\begin{itemize} \n",fip);
+string prl;
+string mol;
+CmdHGroup::iterator it;
+for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
+  if ((*it).first == "All") continue;
+  prl = (*it).first;  check_latex_reflabel(prl);
+  mol = check_latex_underscore((*it).first);
+  fprintf(fip,"\\item {\\bf %s }  (p. \\pageref{%s}) \n", 
+	  mol.c_str(), prl.c_str());
+}
+
+fputs("\\end{itemize} \n",fip);
+
+fputs("\\vspace*{10mm} \n",fip);
+
+CmdExmap::iterator ite;
+fputs("% ----- Liste de toutes les commandes et help item ----- \n",fip);
+fputs("\\vspace{5mm} \n",fip);
+// fputs("\\begin{table}[h!] \n", fip);
+fputs("\\begin{center} \n ", fip);
+fputs("\\rule{2cm}{1mm} List of {\\bf piapp} Help items \\rule{2cm}{1mm} \\\\ \n", fip);
+fputs("\\vspace{3mm} \n",fip);
+fputs("\\begin{tabular}{llllll}  \n", fip);
+int kt = 0;
+for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
+  prl = (*ite).first;  check_latex_reflabel(prl);
+  mol = check_latex_underscore((*ite).first);
+  fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(),  prl.c_str() );
+  kt++;
+  if (kt < 3) fputs(" & ", fip);
+  else  { fputs(" \\\\  \n", fip);  kt = 0; }
+  }
+if (kt == 1) fputs("  &  &  &   \\\\  \n", fip);
+else if (kt == 2)  fputs("  &   \\\\  \n", fip);
+fputs("\\end{tabular} \n", fip);
+fputs("\\end{center} \n", fip);
+//fputs("\\end{table} \n", fip);
+fputs("\\newpage  \n",fip);
+
+int gid;
+for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
+  gid = (*it).second;
+  if (gid == 0)  continue;
+  //  fputs("\\begin{table}[h!] \n",fip);
+  fputs("\\vspace{6mm} \n",fip);
+  fputs("\\begin{center} \n ", fip);
+  fprintf(fip, "\\rule{2cm}{1mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{1mm} \\\\ \n", 
+	  (*it).first.c_str());
+  fputs("\\vspace{3mm} \n",fip);
+  fputs("\\begin{tabular}{llllll} \n", fip);
+  kt = 0;
+  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,"%s & p. \\pageref{%s} ", mol.c_str(),  prl.c_str() );
+    kt++;
+    if (kt < 3) fputs(" & ", fip);
+    else  { fputs(" \\\\  \n", fip);  kt = 0; }
+  }
+  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,"%s & p. \\pageref{%s} ", mol.c_str(),  prl.c_str() );
+    kt++;
+    if (kt < 3) fputs(" & ", fip);
+    else  { fputs(" \\\\  \n", fip);  kt = 0; }
+  }
+  if (kt == 1) fputs("  &  &  &   \\\\  \n", fip);
+  else if (kt == 2)  fputs("  &   \\\\  \n", fip);
+  fputs("\\end{tabular} \n", fip);
+  fputs("\\end{center} \n", fip);
+  //  fputs("\\end{table} \n",fip);
+  //  fputs("\\vspace{5mm} \n",fip);
+}
+// fputs("\\newline \n",fip);
+
+fputs("% ----- Liste des commandes dans chaque groupe ----- \n",fip);
+fputs("\\newpage \n",fip);
+
+for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
+  gid = (*it).second;
+  if (gid == 0)  continue;
+  prl = (*it).first;  check_latex_reflabel(prl);
+  fprintf(fip,"\\subsection{%s} \\label{%s} \n", 
+          (*it).first.c_str(), prl.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);
+return;
+}
+
+
+
Index: /trunk/SophyaLib/SysTools/commander.h
===================================================================
--- /trunk/SophyaLib/SysTools/commander.h	(revision 2446)
+++ /trunk/SophyaLib/SysTools/commander.h	(revision 2446)
@@ -0,0 +1,189 @@
+// This may look like C code, but it is really -*- C++ -*-
+// Classe interpreteur de commande pour piapp 
+// Reza      Aout 97 , Juillet,Aout 98
+//           Octobre 2003: de PIext -> SysTools
+// LAL-IN2P3/CNRS  DAPNIA/CEA
+
+#ifndef COMMANDER_H_SEEN
+#define COMMANDER_H_SEEN
+
+#include "machdefs.h"
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <list>
+#include <stack>
+#include <map>
+#include <functional>
+
+#include "pdlmgr.h"
+#include "dvlist.h"
+#include "ctimer.h"
+
+// Classe definissant l'interface pour un executeur de commande
+
+// Classe definissant l'interface pour un interpreteur de commande
+
+//! Interface definition for a generic command interpreter
+class CmdInterpreter {
+public:
+  virtual		~CmdInterpreter() {} ;
+  virtual string	Name()=0;
+  virtual int		Interpret(string& line)=0;
+};
+
+
+//! Interface definition for command executor, to be used with SOPHYA::Commander
+
+class CmdExecutor {
+public:
+  virtual	~CmdExecutor() {} ;
+  // keyw : Le mot cle associe , args: Arguments de la commande
+  virtual int	Execute(string& keyw, vector<string>& args, string& toks)=0;
+};
+
+
+
+class CommanderBloc;    // Bloc de type foreach / for de l'interpreteur Commander
+class CommanderScript;  // Script de commandes defini ds l'interpreteur Commander
+
+/*
+//! Interface definition for SOPHYA::Commander help manager
+class CommanderHelpMgr {
+public :
+			CommanderHelpMgr();
+  virtual		~CommanderHelpMgr();
+  virtual void		AddHelpGroup(const char * hgrp, int gid);
+  virtual void		AddHelpItem(const char * hitem);
+  virtual void          ClearHelpList();
+  virtual void		Activate();
+}
+*/
+
+
+//! A simple command interpreter with c-shell like syntax with dynamic load capability.
+
+class Commander : public CmdInterpreter  {
+public:
+  static Commander*	GetInterpreter();
+
+			Commander();
+  virtual		~Commander();
+  virtual string	Name();
+
+  virtual void		RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, 
+                                        string grp="Commands");
+  virtual void		RegisterHelp(string& keyw, string& usage, string& grp);
+
+  virtual void		LoadModule(string& fnameso, string& name);
+
+  virtual void		AddInterpreter(CmdInterpreter * cl);
+  virtual void		SelInterpreter(string& name);
+
+  virtual int		Interpret(string& line);
+  virtual int		ParseLineExecute(string& line, bool qw=true);
+  virtual int		ExecuteCommand(string& keyw, vector<string>& args, string& toks);
+  virtual int		ExecFile(string& file, vector<string>& args);
+  virtual int		CShellExecute(string cmd);
+  virtual string&	GetUsage(const string& kw);
+
+  inline  void		SetMaxLoopLimit(int_8 lim=0) { maxlooplimit = lim; }
+  inline  int_8         GetMaxLoopLimit() { return maxlooplimit; }
+
+  string		GetCurrentPrompt() { return curprompt; }
+
+
+  virtual void 		HelptoLaTeX(string const & flnm);
+
+  inline  CmdInterpreter* CurrentInterpreter() { return(curcmdi); }
+
+
+//   Utilitaire pour decoupage en mot
+  static  int   LineToWords(string& line, string& kw, vector<string>& tokens,
+			    string& toks, bool uq=true);
+protected:
+  virtual int	CheckHelpGrp(string& grp);
+  int           ExecuteCommandLine(string & keyw, vector<string> & args,
+				   string & toks);
+
+  int           SubstituteVars(string & s, string & s2);  
+  int	        EvaluateTest(vector<string> & args, 
+			     string & line, bool & res);
+  int	        EvalRPNExpr(vector<string> & args, string & line);
+
+  bool          GetVar(string & vn, string & vv);
+  string        GetVariable(string const & vn);
+  bool          HasVariable(string const & vn);
+  bool          SetVar(string const & vn, string const & vv);
+  bool          DeleteVar(string const & vn);
+  void          ListVars();
+  string        GetTmpDir();
+  inline void   SetCurrentPrompt(string const & pr) { SetCurrentPrompt(pr.c_str()); }
+  virtual void  SetCurrentPrompt(const char* pr);
+
+  virtual void	ShowMessage(const char * msg, int att);
+
+  void          PushStack(vector<string> & args);
+  void          PopStack(bool psta=true);
+
+  CmdInterpreter* curcmdi;
+
+// Gestion des variables
+  DVList variables;
+
+// Pour enregistrer la liste de commandes et leurs executeurs et le help
+  struct cmdex {int group; string us; CmdExecutor * cex; } ;
+  typedef map<string, int, less<string> > CmdHGroup;   // Liste des groupes de commandes
+  CmdHGroup cmdhgrp;
+  int cmdgrpid;                                     // Numero de groupe courant
+  typedef map<string, cmdex, less<string> > CmdExmap;
+  CmdExmap cmdexmap;
+  CmdExmap helpexmap;                               // Pour les helps sans commande
+
+// Pour garder la liste des modules 
+  typedef map<string, PDynLinkMgr* , less<string> > Modmap;
+  Modmap modmap;
+
+// Pour garder la liste des interpreteur
+  typedef map<string, CmdInterpreter*, less<string> > InterpMap;
+  InterpMap interpmap;
+ 
+//  Pour stocker les scripts definis ds l'interpreteur
+  typedef map<string, CommanderScript*, less<string> > ScriptList;
+  ScriptList mScripts;  // Liste des scripts
+  CommanderScript* curscript; // Script en cours de definition
+
+//  Pour stocker les alias definies par l'interpreteur
+  typedef map<string, string, less<string> > CmdStrList;
+  CmdStrList mAliases;  // Liste des alias 
+
+// Le stack pour les arguments des .pic et des scripts
+  stack< vector<string> > ArgsStack;
+// Stack pour les Prompts
+  stack<string> PromptStack; 
+
+  stack< CommanderBloc * > CmdBlks;  // Bloc de commande courant (foreach, ...)
+  int felevel;                    // foreach-for level 
+  int_8 maxlooplimit;            // Limite maximum des boucles
+  stack< list<char> > TestsStack; // Stack des resultats de test
+  list<char>::iterator tresit;       // Test courant
+  bool curtestresult;             // Resultat courant des tests 
+
+  bool mulinefg;            // Bloc multi-lignes (ligne suite)
+  string mulinecmd;         // Commande multi-lignes
+  string spromptmul;        // Prompt console avant multi-ligne
+  string curprompt;
+
+  ofstream hist;       //  History file 
+  bool histon;        //  True ->  history file
+  bool trace;          // Trace flag
+  bool timing;         // Display CPU Time
+  Timer* gltimer;      // pour Display CPU Time
+
+};
+
+
+/* end of ifdef COMMANDER_H_SEEN */
+#endif  
+
Index: /trunk/SophyaLib/SysTools/objlist.list
===================================================================
--- /trunk/SophyaLib/SysTools/objlist.list	(revision 2445)
+++ /trunk/SophyaLib/SysTools/objlist.list	(revision 2446)
@@ -1,2 +1,3 @@
+commander.o
 ctimer.o
 cxxcmplnk.o
