Index: trunk/SophyaLib/SysTools/commander.cc
===================================================================
--- trunk/SophyaLib/SysTools/commander.cc	(revision 2615)
+++ trunk/SophyaLib/SysTools/commander.cc	(revision 2671)
@@ -12,4 +12,5 @@
 #include "rpneval.h"
 #include "srandgen.h"
+#include "zthread.h"
 
 
@@ -331,4 +332,54 @@
 }
 
+
+// ------------------------------------------------------------
+//         Classe CommandExeThr
+// ------------------------------------------------------------
+/*!
+  \internal
+  \class SOPHYA::CommandExeThr
+  \ingroup SysTools 
+  Class for internal use by class Commander for command execution in separate threads.
+*/
+class CommandExeThr :  public ZThread  {
+public:
+                 CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw, 
+			       vector<string>& args, string& toks);
+  virtual void   run();
+  inline  uint_8 Id() { return _id; }
+  inline  bool   IfDone() { return _fgdone; }
+  inline  string& Tokens() { return  _toks; }
+  inline  string& Keyword() { return  _keyw; }
+protected:
+  uint_8 _id;
+  CmdExecutor * _cmdex;
+  string _keyw, _toks;
+  vector<string> _args;
+  bool _fgdone;
+};
+
+/* --Methode-- */
+CommandExeThr::CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw, 
+			       vector<string>& args, string& toks)
+{
+  _id = id;
+  _cmdex = cmdex;
+  _keyw = keyw;
+  if (args.size() > 1)
+    for(size_t k=0; k<args.size()-1; k++) _args.push_back(args[k]); 
+  _toks = toks;
+  for(size_t k=_toks.size()-1; k>0; k--) 
+    if (_toks[k] == '&') { _toks[k] = ' '; break; }
+  _fgdone = false;
+}
+
+/* --Methode-- */
+void CommandExeThr::run()
+{
+  int rc = _cmdex->Execute(_keyw, _args, _toks);
+  _fgdone = true;
+  setRC(rc);
+}
+
 // ------------------------------------------------------------
 //         Classe Commander
@@ -345,5 +396,5 @@
   to applications. 
 
-  Although the insterpreter has many limitations compared to 
+  Although the interpreter has many limitations compared to 
   c-shell, or Tcl , it provides some interesting possibilities:
 
@@ -400,4 +451,7 @@
 curtestresult = true;
 
+// Pour la numerotation et l'identification des threads
+ThrId = 0;
+
 // 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
@@ -411,5 +465,5 @@
 string usage;
 usage = ">>> (Commander) Interpreter's keywords : \n";
-usage += "  > set varname string   # To set a variable, $varname \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";
@@ -436,4 +490,8 @@
 usage += "  > listscripts   # List of all known scripts \n";
 usage += "  > clearcript    # Clear a script definition \n";
+usage += "  > thrlist       # List of command execution threads (& as the last character) \n";
+usage += "  > clearthrlist  # Removes finished threads from the list  \n";
+usage += "  > cancelthr Id  # Cancel a given thread (ThrId=id)  \n";
+usage += "  > waitthr       # Waits until all active threads have finished (join()) \n";
 usage += "  > exec filename # Execute commands from file \n";
 usage += "  > help <command_name>  # <command_name> usage info \n";   
@@ -475,4 +533,15 @@
 RegisterCommand(kw, usage, NULL, grp);
 
+kw = "CExpEvaluator";
+usage  = "> Evaluation of C-like expression (used in V = C-like-Expression) \n";
+usage += "   >>> Arithmetic operators, parenthesis ( + - * / ) \n";
+usage += "   >>> Functions : sqrt fabs floor hypot \n";
+usage += "   ...  exp log log10 pow  ; sinh cosh tanh \n";
+usage += "   ...  sin cos tan asin acos atan atan2  \n";
+usage += "   ...  rand01()  randpm1() gaurand() \n";
+usage += "   >>> Constants : Pi = M_PI E = M_E \n";
+usage += "   Example: x = 5.*(2.+sin(0.3*Pi))";
+RegisterCommand(kw, usage, NULL, grp);
+
 kw = "shell execute";
 usage  = "> shell  command_string  # Execute  shell command\n";
@@ -656,5 +725,5 @@
 /* --Methode-- */
 /*!
-  \brief Method which has to be invoked to interpret a giev command line or string.
+  \brief Method which has to be invoked to interpret a given command line or string.
 */
 int Commander::Interpret(string& s)
@@ -662,4 +731,11 @@
 int rc = 0;
 ScriptList::iterator sit;
+
+// Si le flag d'arret d'execution a ete positionne on returne avec le code
+//  de BREAKEXECUTION
+if (fgexebrk) { 
+  cout << " ===> Commander::Interpret() - STOP Execution (CMD_BREAKEXE_RC)" << endl; 
+  fgexebrk = false; return CMD_BREAKEXE_RC; 
+}
 
 // On saute de commandes vides
@@ -769,5 +845,5 @@
 // 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++;
+  if ( (kw == "for") || (kw == "foreach") || (kw == "forinfile") ) felevel++;
   else if (kw == "end") felevel--;
   if (felevel == 0) { // Il faut executer le bloc
@@ -777,5 +853,5 @@
     if (!curb->CheckBloc()) {
       cerr << "Commander::Interpret()/syntax error - unbalenced if ... endif"
-	   << " within for/foreach bloc ! " << endl;
+	   << " within for/foreach/forinfile bloc ! " << endl;
       delete curb;
       _xstatus = 93;
@@ -803,5 +879,5 @@
 }
 else if (kw == "end") {
-  cerr << "Commander::Interpret()/syntax error - end outside for/foreach bloc \n"
+  cerr << "Commander::Interpret()/syntax error - end outside for/foreach/forinfile bloc \n"
        << "line: " << s << endl;
   _xstatus = 94;
@@ -1001,4 +1077,9 @@
 
 return(0);
+}
+
+void  Commander::StopExecution()
+{
+  fgexebrk = true;
 }
 
@@ -1762,4 +1843,26 @@
   }
 }
+//---------------------------------------------
+//---   Commandes de gestion des threads ------
+//---------------------------------------------
+else if (kw == "thrlist") {
+  ListThreads();
+  return(0);
+}
+else if (kw == "cancelthr") {
+  if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: cancelthr thrid" << endl;  return(0); }
+  uint_8  id = atol(tokens[0].c_str());
+  CancelThr(id);
+  return (0);
+}
+else if (kw == "waitthr") {
+  WaitThreads();
+  return (0);
+}
+else if (kw == "cleanthrlist") {
+  CleanThrList();
+  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; }
@@ -1820,5 +1923,16 @@
   if (it == cmdexmap.end())  cout << "No such command : " << keyw << " ! " << endl;
   else { 
-    if ((*it).second.cex) rc = (*it).second.cex->Execute(keyw, args, toks);
+    if ((*it).second.cex) {
+      // Doit-on l'executer sous forme de thread separe ? 
+      if ((args.size()>0) && (args[args.size()-1] == "&")) {
+	ThrId++;
+	CommandExeThr * thr = new CommandExeThr(ThrId, (*it).second.cex, keyw, args, toks);
+	CmdThrExeList.push_back(thr);
+	cout << " Commander::ExecuteCommand() : Thread execution of command " << keyw << endl;
+	thr->start();    
+	rc = 0;
+      }
+      else rc = (*it).second.cex->Execute(keyw, args, toks);
+    }
     else cout << "Dont know how to execute " << keyw << " ? " << endl;
     }
@@ -1877,4 +1991,67 @@
 
 return(0);
+}
+
+/* --Methode-- */
+void Commander::ListThreads()
+{
+  cout << "---- Commander::ListThreads()  List of separate execution threads NThread=" 
+       <<  CmdThrExeList.size() << " ----- " << endl;
+  for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin(); 
+      tit != CmdThrExeList.end(); tit++) {
+    cout << "Id=" << (*tit)->Id(); 
+    if ( (*tit)->IfDone() )  cout << " Finished , Rc= " << (*tit)->getRC();
+    else cout << " Executing";
+    cout << " (Cmd= " << (*tit)->Keyword() << " " << (*tit)->Tokens() << " )" << endl; 
+  }
+}
+/* --Methode-- */
+void Commander::CancelThr(uint_8 id)
+{
+  for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin(); 
+      tit != CmdThrExeList.end(); tit++) {
+    if ((*tit)->Id() == id) { 
+      (*tit)->cancel();  
+      cout << "Commander::CancelThr()  Thread Id= " << id << " cancelled" << endl;
+      return;
+    }
+  }
+  cout << "Commander::CancelThr()/Error: No thread with Id= " << id << endl;
+}
+
+/* --Methode-- */
+void Commander::CleanThrList()
+{
+  cout << "---- Commander::CleanThrList()  Cleaning thrlist  ----- \n";
+  list<CommandExeThr *> thrcopie;
+  for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin(); 
+      tit != CmdThrExeList.end(); tit++) {
+    if ( (*tit)->IfDone() ) { 
+      cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
+      delete (*tit);
+    }
+    else thrcopie.push_back((*tit));
+  }
+  CmdThrExeList = thrcopie;
+  cout << " ... " << CmdThrExeList.size() << " threads still active " << endl;
+}
+
+/* --Methode-- */
+void Commander::WaitThreads()
+{
+  cout << "---- Commander::WaitThreads()  Wait/Join command execution threads - NThread=" 
+       <<  CmdThrExeList.size() << " ----- " << endl;
+  for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin(); 
+      tit != CmdThrExeList.end(); tit++) {
+    try {
+      if (! (*tit)->IfDone())  (*tit)->join();
+    }
+    catch (std::exception & e) {
+      cout << " Commander::WaitThreads()/Exception msg= " << e.what() << endl;
+    }
+    cout << " Joined thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << endl;
+    delete (*tit);
+  }
+  CmdThrExeList.erase(CmdThrExeList.begin(), CmdThrExeList.end());
 }
 
