Index: trunk/SophyaPI/PIext/piacmd.cc
===================================================================
--- trunk/SophyaPI/PIext/piacmd.cc	(revision 2218)
+++ trunk/SophyaPI/PIext/piacmd.cc	(revision 2236)
@@ -147,4 +147,8 @@
   PIACmdBloc*	Execute();
   inline int&   TestLevel()  { return testlevel; }
+  inline int&   LoopLevel()  { return looplevel; }
+  inline bool   CheckBloc() 
+    { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)); }
+  
 protected:
   PIACmd* piacmd;
@@ -160,4 +164,6 @@
   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 
 };
 
@@ -171,5 +177,7 @@
 i1 = 0;  i2 = -1;  di = 1;
 f1 = 0.; f2 = -1.; df = 1.;
-testlevel = 0;
+testlevel = looplevel = 0;
+scrdef = false;
+
 if ((args.size() < 2) ||  !isalpha((int)args[0][0]) )  return; 
 if ((kw != "foreach") && (kw != "for"))  return;
@@ -230,4 +238,7 @@
   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; 
 }
 
@@ -302,12 +313,77 @@
 }
 
-// ------------------
-//  Classe PIACmdScript 
-// ------------------
+// ---------------------------------------------------------------
+//                  Classe PIACmdScript 
+//   Definition et execution d'un script de PIACmd
+//   script : Une liste de commande PIACmd - Lors de l'execution, 
+//   les variables-argument $# $0 $1 sont definies. 
+// ---------------------------------------------------------------
+
 class PIACmdScript {
 public:
-  PIACmdScript();
+  PIACmdScript(PIACmd* piac, string const& name, string const& comm);
   virtual ~PIACmdScript();
+
+  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:
+  PIACmd* piacmd;
+  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-- */
+PIACmdScript::PIACmdScript(PIACmd* piac, string const& name, 
+			   string const& comm)
+{
+piacmd = piac;
+testlevel = looplevel = 0;
+scrdef = false;
+mName = name;
+if (!isalpha(name[0]))  fgok = false;
+else fgok = true;
+mComm = comm;
+}
+
+/* --Methode-- */
+PIACmdScript::~PIACmdScript()
+{
+}
+
+/* --Methode-- */
+void PIACmdScript::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 PIACmdScript::Execute(vector<string>& args)
+{
+  if (!CheckScript()) return(-1);
+  cout << " PIACmdScript::Execute() - Executing script " << Name() << endl;
+  for(int k=0; k<lines.size(); k++) {
+    if (piacmd->Interpret(lines[k]) == 77777) break;
+  }
+  return(0);
+}
 
 // ------------------------------------------------------------
@@ -330,4 +406,5 @@
 mulinecmd = "";
 mulinefg = false;
+curscript = NULL;
 
 CmdBlks.push(NULL);
@@ -362,7 +439,10 @@
 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"; 
@@ -412,4 +492,8 @@
   delete (*it).second;
   }
+
+for(ScriptList::iterator sit = mScripts.begin();
+    sit != mScripts.end(); sit++) delete (*sit).second; 
+ 
 delete helpwin;
 delete cxxexwin;
@@ -549,5 +633,5 @@
 int rc = 0;
 NamedObjMgr omg;
-
+ScriptList::iterator sit;
 
 // On saute de commandes vides
@@ -608,8 +692,8 @@
 
 // les mot-cle end else endif doivent etre le seul mot de la ligne
-if ( (kw == "end") || (kw == "else") || (kw == "endif") ) {
+if ( (kw == "end") || (kw == "else") || (kw == "endif") || (kw == "endscript") ) {
   size_t ltk = toks.length();
   if (toks.find_first_not_of(" \t") < ltk) {
-    cerr << "PIACmd::Interpret()/syntax error near end else endif \n"
+    cerr << "PIACmd::Interpret()/syntax error near end else endif endscript \n"
 	 << "line: " << s << endl;
     return(1);
@@ -617,4 +701,34 @@
 }
 
+// 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 << "PIACmd::Interpret() replacing script " 
+	     << curscript->Name() << endl;
+	PIACmdScript* scr = mScripts[curscript->Name()];
+	mScripts.erase(sit);
+	delete scr;
+      }
+      cout << "PIACmd::Interpret() Script " << curscript->Name() 
+	   << " defined successfully" << endl;
+      mScripts[curscript->Name()] = curscript;
+      mImgApp->GetConsole()->SetPrompt("Cmd> ");
+      curscript = NULL;
+      return(0);
+    }
+    else {
+      cout << "PIACmd::Interpret() Error in Script " << curscript->Name() 
+	   << " definition " << endl;
+      mImgApp->GetConsole()->SetPrompt("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
@@ -625,5 +739,5 @@
     CmdBlks.top() = curb->Parent();
     mImgApp->GetConsole()->SetPrompt("Cmd> ");
-    if (curb->TestLevel() != 0) {
+    if (!curb->CheckBloc()) {
       cerr << "PIACmd::Interpret()/syntax error - unbalenced if ... endif"
 	   << " within for/foreach bloc ! " << endl;
@@ -727,5 +841,5 @@
 // Execution de code C++
 
-if (s[0] == '@')   { 
+if (kw == "@@") {
   CxxExecutor * cxxe = dynamic_cast<CxxExecutor *>(cxxexec);
   if (cxxe == NULL) {
@@ -733,11 +847,5 @@
     return(99);
   }
-  // Sans substitution des variables $
-  if (s[1] == '@') return(cxxe->ExecuteCXX(s.substr(2)));
-  else { // AVEC substitution des variables $
-    rcs = SubstituteVars(s, s2);
-    if (rcs) return(rcs);
-    return(cxxe->ExecuteCXX(s2.substr(1)));    
-  }
+  return(cxxe->ExecuteCXX(s.substr(2)));
 }
 
@@ -748,5 +856,5 @@
 // >>>> Separating keyword and tokens 
 vector<string> tokens;
-
+/*
 q = s2.find(' '); 
 l = s2.length();
@@ -773,6 +881,7 @@
   tokens.push_back(token);
   }
-
-
+*/
+/* 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")) {
@@ -805,12 +914,75 @@
   mImgApp->GetConsole()->SetPrompt(npr);
 }
-//  Execution de commandes 
-else rc = ExecuteCommandLine(kw, tokens, toks);
-return(rc);
-
+else if (kw == "@") {  // Evaluation d'expression
+  int rcev = EvalVarExpr(tokens, s);
+  if (rcev) {
+    cerr << "PIACmd::Interpret() evaluation syntax Error ! " << endl;
+    return(1);
+  }
+  return(0);
+}
+else if (kw == "defscript") {  // definition de script
+  curscript = new PIACmdScript(this, tokens[0], tokens[1]);
+  mImgApp->GetConsole()->SetPrompt("Script...> ");
+  return(0);
+}
+else {
+  //  Si c'est le nom d'un script 
+  sit = mScripts.find(kw);
+  if (sit != mScripts.end()) {
+    bool ohv = histon;
+    histon = false; 
+    PushStack(tokens);
+    (*sit).second->Execute(tokens);
+    PopStack(true);
+    histon = ohv;
+  }
+  //  Execution de commandes 
+  else rc = ExecuteCommandLine(kw, tokens, toks);
+  return(rc);
+}  
 // cout << "PIACmd::Do() DBG  KeyW= " << kw << " NbArgs= " << tokens.size() << endl;
 //  for(int ii=0; ii<tokens.size(); ii++)
 //  cout << "arg[ " << ii << " ] : " << tokens[ii] << endl;
 
+}
+
+
+/* --Methode-- */
+int PIACmd::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 << "PIACmd::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);
 }
 
@@ -1016,4 +1188,64 @@
 }
 
+/* Verification la presence d'argument d'operation */
+#define _Check_EvalVarArg(j_) if (j_ >= args.size()) { \
+  cerr << "PIACmd::EvalVarExpr: syntax error " << line << endl; \
+  return(1); }
+  
+/* --Methode-- */
+int PIACmd::EvalVarExpr(vector<string> & args, string & line)
+{
+  if ((args.size() < 3) || (args[1] != "=") || !isalpha(args[0][0]) )  { 
+    cerr << " PIACmd::EvalVarExpr: syntax error " << line << endl;
+    return(1);
+  }
+
+  double x = atof(args[2].c_str());
+  double y = 0.;
+  int k = 3;
+  while (k < args.size()) {
+    if (args[k] == "+") { 
+      _Check_EvalVarArg(k+1);
+      y = atof(args[k+1].c_str());
+      x += y;  k += 2;
+    }
+    else if (args[k] == "-") { 
+      _Check_EvalVarArg(k+1);
+      y = atof(args[k+1].c_str());
+      x -= y;  k += 2;
+    }
+    else if (args[k] == "*") { 
+      _Check_EvalVarArg(k+1);
+      y = atof(args[k+1].c_str());
+      x *= y;  k += 2;
+    }
+    else if (args[k] == "/") { 
+      _Check_EvalVarArg(k+1);
+      y = atof(args[k+1].c_str());
+      x /= y;  k += 2;
+    }
+    else if (args[k] == "//") { 
+      _Check_EvalVarArg(k+1);
+      if (args[k+1] == "sin")  x = sin(x);
+      else if (args[k+1] == "cos")  x = cos(x);
+      else if (args[k+1] == "tan")  x = tan(x);
+      else if (args[k+1] == "asin")  x = asin(x);
+      else if (args[k+1] == "acos")  x = acos(x);
+      else if (args[k+1] == "atan")  x = atan(x);
+      else if (args[k+1] == "log")   x = log(x);
+      else if (args[k+1] == "log10") x = log10(x);
+      else if (args[k+1] == "exp")   x = exp(x);
+      k += 2;
+   }
+  }
+
+  NamedObjMgr& omg = *mObjMgr;
+  char buff[64];
+  sprintf(buff, "%g", x);
+  string vv = buff;
+  omg.SetVar(args[0], vv); 
+  return(0);
+}
+
 /* --Methode-- */
 void PIACmd::PushStack(vector<string>& args)
@@ -1155,5 +1387,5 @@
   }
 else if (kw == "listcommands") {
-  cout << "---- PIACmd::Interpret()  Command Variable List ----- \n";
+  cout << "---- PIACmd::Interpret() Command List ----- \n";
   CmdExmap::iterator it;
   int kc = 0;
@@ -1165,4 +1397,28 @@
   cout << endl;
   }
+else if (kw == "listscripts") {
+  cout << "---- PIACmd::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 << "PIACmd::Interpret() Usage: clearscript scriptname" << endl;  
+    return(0); 
+  }
+  ScriptList::iterator sit = mScripts.find(tokens[0]);
+  if (sit == mScripts.end()) {
+    cout << "PIACmd::Interpret() No script with name" << tokens[0] << endl;
+    return(0);
+  }
+  else {
+    delete (*sit).second;
+    mScripts.erase(sit);
+    cout << "PIACmd::Interpret() script " << tokens[0] << " cleared" << endl;
+    return(0);
+  }
+}
 else if (kw == "traceon")  { cout << "PIACmd::Interpret()  -> Trace ON mode " << endl; trace = true; }
 else if (kw == "traceoff") { cout << "PIACmd::Interpret()  -> Trace OFF mode " << endl; trace = false; }
@@ -1201,30 +1457,11 @@
 
 /* --Methode-- */
-int PIACmd::ParseLineExecute(string& line)
+int PIACmd::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);
-
-string toks,kw;
-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(" ",q+1); // au debut d'un token
-  if (p>=l) break;
-  q = toks.find_first_of(" ",p); // la fin du token;
-  string token = toks.substr(p,q-p);
-  tokens.push_back(token);
-  }
-
+LineToWords(line, kw, tokens, toks, qw);
 return(ExecuteCommand(kw, tokens, toks));  
 }
