Index: trunk/SophyaLib/SysTools/commander.cc
===================================================================
--- trunk/SophyaLib/SysTools/commander.cc	(revision 2512)
+++ trunk/SophyaLib/SysTools/commander.cc	(revision 2518)
@@ -2,4 +2,5 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <ctype.h>
 #include <math.h>
@@ -13,4 +14,10 @@
 
 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, ...)    
@@ -36,5 +43,10 @@
   inline void	AddBloc(CommanderBloc* blk)  
     { blocs.push_back(blk); bloclineid.push_back(-blocs.size()); }
-  CommanderBloc*	Execute();
+
+  // 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; }
@@ -74,13 +86,23 @@
 if ((args.size() < 2) ||  !isalpha((int)args[0][0]) )  return; 
 if ((kw != "foreach") && (kw != "for") && (kw != "forinfile"))  return;
-varname = args[0];  // $CHECK$ Variable name should be checked 
+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] != ")") ) return;
-  for(int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
+  if ( (args[1] == "(") && (args[args.size()-1] == ")") ) {
+    // foreach varname ( w1 w2 w3 ... ) 
+    for(int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
+  }
+  else {
+    // foreach varname WordVectorName 
+    if (!piac->GetVar(args[1], strlist))  return;
+  }
+  if (strlist.size() < 1)  return;
   typ = BT_ForeachList;
   blkok = true;
@@ -140,12 +162,7 @@
 
 /* --Methode-- */
-CommanderBloc* CommanderBloc::Execute()
-{
-// cout << " DBG * CommanderBloc::Execute() " << typ << " - " << bloclineid.size() <<
-//      " I1,I2=" << i1 << " , " << i2 << " , " << di << endl;
-string cmd;
+int CommanderBloc::Execute()
+{
 int k=0;
-int kj=0;
-int kk=0;
 char buff[32];
 int rcc = 0;
@@ -154,20 +171,28 @@
 
 if (typ == BT_ForeachLineInFile) {  // foreach line in file loop
-}
-else if (typ == BT_ForeachList)   // foreach string 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; 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
+    rcc = ExecuteOnce(strlist[k]);
+    if (rcc == CMD_BREAKEXE_RC)  return rcc;
+    else if (rcc == CMD_BREAK_RC)  break; 
+  }  
+}
+else if (typ == BT_ForeachInt)  { // Integer loop
   for(int i=i1; i<i2; i+=di) {
     k++;
@@ -176,19 +201,13 @@
       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) {
+    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; f<f2; f+=df) {
     k++;
     if ((mxloop>0) && (k > mxloop)) {
@@ -196,19 +215,32 @@
       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); 
+    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<bloclineid.size(); kj++) {
+    rcc = 0;
+    kk = bloclineid[kj]; 
+    if (kk > 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;
 }
 
@@ -286,10 +318,12 @@
 int CommanderScript::Execute(vector<string>& args)
 {
+  int rcc;
   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);
+    rcc = _commander->Interpret(lines[k]);
+    if ( (rcc == CMD_BREAKEXE_RC) || (rcc == CMD_RETURN_RC) ) break; 
+  }
+  return(rcc);
 }
 
@@ -330,4 +364,7 @@
  _retstr = "";
 
+// Controle du flot d'execution 
+ fgexebrk = false;
+
 CmdBlks.push(NULL);
 list<char> xtx;
@@ -347,17 +384,16 @@
 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 += "  > 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";
@@ -373,5 +409,7 @@
 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 += "  > help <command_name>  # <command_name> 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);
@@ -778,8 +816,8 @@
 
 // Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
-if (kw == "break") return(77766);
+if (kw == "break") return CMD_BREAK_RC;
 else if (kw == "return")  { 
   _retstr = toks; 
-  return(77777);
+  return CMD_RETURN_RC;
 }
 
@@ -797,6 +835,7 @@
 // >>>> Separating keyword and tokens 
 vector<string> tokens;
+vector<bool> qottoks;
 /* decoupage en mots */
-LineToWords(s2, kw, tokens, toks, true);
+LineToWords(s2, kw, tokens, qottoks, toks, true);
 
 // Si c'est un for/foreach, on cree un nouveau bloc
@@ -834,17 +873,31 @@
 else if ((tokens.size() > 0) && (tokens[0] == "=")) {  
   // x = Expression 
-  try {
-    CExpressionEvaluator cex(tokens[1]);
-    double res = cex.Value();
-    char cbuff[64];
-    sprintf(cbuff,"%g",res);
-    string vv = cbuff;
-    SetVariable(kw, vv);
-  }
-  catch (CExprException& cexerr) {
-    cerr << "Commander::Interpret() evaluation Error : \n " << "line: " << s 
-	 << " \n Msg=" << cexerr.Msg()  << endl;
-    _xstatus = 98;
-    return(98);
+  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<tokens.size(); js++)  sex += tokens[js];
+	CExpressionEvaluator cex(sex);
+	res = cex.Value();
+      }
+      else {
+	CExpressionEvaluator cex(tokens[1]);
+	res = cex.Value();
+      }
+      char cbuff[64];
+      sprintf(cbuff,"%g",res);
+      string vv = cbuff;
+      SetVariable(kw, vv);
+    }
+    catch (CExprException& cexerr) {
+      cerr << "Commander::Interpret() evaluation Error : \n " << "line: " << s 
+	   << " \n Msg=" << cexerr.Msg()  << endl;
+      _xstatus = 98;
+      return(98);
+    }
   }
 }
@@ -889,5 +942,5 @@
 /* --Methode-- */
 int Commander::LineToWords(string& line, string& kw, vector<string>& tokens, 
-			string& toks, bool uq)
+			   vector<bool>& qottoks, string& toks, bool uq)
 {
 if (line.length() < 1)  return(0);
@@ -905,4 +958,5 @@
 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;
@@ -913,5 +967,5 @@
       return(-1);
     }
-    p++;
+    p++;  swq = true;  
   }
   else {
@@ -919,5 +973,7 @@
   }
   string token = toks.substr(p,q-p);
-  tokens.push_back(token);  nw++;
+  tokens.push_back(token); 
+  qottoks.push_back(swq);
+  nw++;
   }
 
@@ -1048,5 +1104,5 @@
 {
 if (vn.length() < 1) {
-  cerr << " Commander::SubstituteVar/Error: length(varname=" << vn << ")<1 !" << endl;
+  cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
   vv = "";    return(false);
 }
@@ -1057,5 +1113,5 @@
 if (vn == "#") {
   if (ArgsStack.empty()) {
-    cerr << " Commander::SubstituteVar/Error: ArgsStack empty ! " 
+    cerr << " Commander::Var2Str/Error: ArgsStack empty ! " 
 	 << " ($" << vn << ")" << endl;
     vv = "";  return(false);
@@ -1063,15 +1119,26 @@
   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<ArgsStack.top().size(); ssk++)  vv += ArgsStack.top()[ssk];
+  return(true);
+}
 else if (ctoi(vn.c_str(), &ka) > 0) {  // $0 $1 $2 ...
   if (ArgsStack.empty()) {
-    cerr << " Commander::SubstituteVar/Error: ArgsStack empty ! " 
+    cerr << " Commander::Var2Str/Error: ArgsStack empty ! " 
 	 << " ($" << vn << ")" << endl;
     vv = ""; return(false);
   }
   if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) {
-    cerr << " Commander::SubstituteVar/Error: Undefined variable ! " 
+    cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size()  ! " 
 	 << " ($" << vn << ")" << endl;
     vv = ""; return(false);
@@ -1082,5 +1149,5 @@
   CmdVarList::iterator it = variables.find(vn.substr(1));
   if (it == variables.end()) {
-    cerr << " Commander::SubstituteVarError: Undefined variable " 
+    cerr << " Commander::Var2Str/Error #vname Undefined variable " 
 	 << vn << " ! " << endl;
     vv = "";  return(false);
@@ -1094,5 +1161,5 @@
   return true;
 }
-else if (vn == "retstr") {
+else if ((vn == "retstr") || (vn == "retval")) {
   vv = _retstr;
   return true;
@@ -1103,5 +1170,5 @@
   else if (GetVarEnv(vn, vv))  return true;
   else { 
-    cerr << " Commander::SubstituteVarError: Undefined variable " 
+    cerr << " Commander::Var2Str/Error  Undefined variable " 
 	 << vn << " ! " << endl;
     vv = "";  return false;
@@ -1316,5 +1383,5 @@
 {
   vv = "";
-  cout << " Commander::GetVarApp() Not available ! " << endl;
+  //  cout << " Commander::GetVarApp() Not available ! " << endl;
   return false;
 }
@@ -1323,5 +1390,5 @@
 bool Commander::SetVarApp(string const & vn, string const & vv)
 {
-  cout << " Commander::SetVarApp() Not available ! " << endl;
+  //  cout << " Commander::SetVarApp() Not available ! " << endl;
   return false;  
 }
@@ -1330,5 +1397,5 @@
 bool Commander::DeleteVarApp(string const & vn)
 {
-  cout << " Commander::DeleteVarApp() Not available ! " << endl;
+  //  cout << " Commander::DeleteVarApp() Not available ! " << endl;
   return false;  
 }
@@ -1337,5 +1404,5 @@
 void Commander::ListVarApp()
 {
-  cout << " Commander::ListVarApp() Not available ! " << endl;
+  //  cout << " Commander::ListVarApp() Not available ! " << endl;
   return;  
 }
@@ -1345,7 +1412,13 @@
 bool Commander::GetVarEnv(string const & vn, string & vv)
 {
-  vv = "";
-  cout << " Commander::GetVarEnv() Not available ! " << endl;
-  return false;
+  char* vev = getenv(vn.c_str());
+  if (vev) {
+    vv = vev;
+    return true;
+  }
+  else { 
+    vv = "";
+    return false;
+  }
 }
 
@@ -1353,6 +1426,9 @@
 bool Commander::SetVarEnv(string const & vn, string const & vv)
 {
-  cout << " Commander::SetVarEnv() Not available ! " << endl;
-  return false;  
+  string pev = vn;
+  pev += '=';
+  pev += vv;
+  if (putenv(pev.c_str()) == 0)  return true;
+  else return false;  
 }
 
@@ -1360,5 +1436,5 @@
 bool Commander::DeleteVarEnv(string const & vn)
 {
-  cout << " Commander::DeleteVarEnv() Not available ! " << endl;
+  //  cout << " Commander::DeleteVarEnv() Not available ! " << endl;
   return false;  
 }
@@ -1460,35 +1536,57 @@
     }
   }
+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" << endl;  return(0); }
+  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 {
-    vector<string> vv;
-    for(int k=1; k<tokens.size(); k++)  vv.push_back(tokens[k]);
-    SetVar(tokens[0], vv);
+    if ( (tokens[1] != "(") || (tokens[tokens.size()-1] != ")") ) {
+    cout << "Commander::Interpret() Usage: set vecvar ( w1 w2 ... ) " << endl;  
+    return(1); 
+    }
+    string vname = tokens[0];
+    vector<string>::iterator vit;
+    vit = tokens.begin(); tokens.erase(vit);
+    vit = tokens.begin(); tokens.erase(vit);
+    tokens.pop_back();
+    SetVar(vname, tokens);
   }
   return 0;
 }
-/*  RZDELETE
-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]) );
-  }
-  END-RZDELETE */
+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<string> 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(0);
+    return(1);
   }
   string xx = tokens[1];
@@ -1500,5 +1598,5 @@
   if (tokens.size() < 1) { 
     cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;  
-    return(0); 
+    return(1); 
   }
   else DeleteVar(tokens[0]);
@@ -1529,5 +1627,5 @@
   if (tokens.size() < 1) {
     cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;  
-    return(0);
+    return(1);
   }
   ofstream ofs(tokens[0].c_str(), ios::app);
@@ -1634,7 +1732,8 @@
 {
 vector<string> tokens;
+vector<bool> qottoks;
 string kw, toks;
 if (line.length() < 1)  return(0);
-LineToWords(line, kw, tokens, toks, qw);
+LineToWords(line, kw, tokens, qottoks, toks, qw);
 return(ExecuteCommand(kw, tokens, toks));  
 }
@@ -1658,5 +1757,5 @@
 char line_buff[512];
 FILE *fip;
-
+int rcc = 0;
 if ( (fip = fopen(file.c_str(),"r")) == NULL ) {
   if (file.find('.') >= file.length()) {
@@ -1675,5 +1774,4 @@
 
 // hist << "### Executing commands from " << file << endl;
-
 PushStack(args);
 if (trace) { 
@@ -1690,5 +1788,6 @@
   line_buff[strlen(line_buff)-1] = '\0';   /*  LF/CR de la fin */
   string line(line_buff);
-  if (Interpret(line) == 77777) break;
+  rcc = Interpret(line);
+  if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
   }
 histon = ohv; 
