#include "piacmd.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

#include "basexecut.h"

#include "pdlmgr.h"
#include "ctimer.h"
#include "strutil.h"
#include "strutilxx.h"
// #include "dlftypes.h"
#ifdef SANS_EVOLPLANCK
#include "nbrandom.h"
#else
#include "srandgen.h"
#endif

#include "pistdimgapp.h"
#include "nobjmgr.h"
#include "piafitting.h"
#include "pawexecut.h"
#include "cxxexecutor.h"
#include "cxxexecwin.h"
#include "contmodex.h" 
#include "flowmodex.h"

#include PISTDWDG_H 
#include PILIST_H 

// ------------------------------------------------------------
//         Gestion d'une fenetre d'aide interactive  
//                    Classe   PIAHelpWind   
// ------------------------------------------------------------

class PIAHelpWind : public PIWindow {
public :
		PIAHelpWind(PIStdImgApp* par, PIACmd* piacmd);
  virtual	~PIAHelpWind();
  virtual void  Show();
  virtual void  Process(PIMessage msg, PIMsgHandler* sender, void* data=NULL);
  inline  void  AddHelpGroup(const char * hgrp, int gid)
                    { hgrpom->AppendItem(hgrp, 20000+gid); }
  inline  void  ClearHelpList() 
                    { mNitem=0; hitemlist->DeleteAllItems(); }
  inline  void	AddHelpItem(const char * hitem) 
		    { mNitem++;  hitemlist->AppendItem(hitem, 100+mNitem); }
protected :
  PIStdImgApp* dap;
  PIACmd* piac;
  int mNitem;
  PIList* hitemlist;
  PIOptMenu* hgrpom;
  PIButton * mBut;
  PILabel * mLab;
  PIText* mTxt;
};

/* --Methode-- */
PIAHelpWind::PIAHelpWind(PIStdImgApp *par, PIACmd* piacmd)
  : PIWindow((PIMsgHandler *)par, "Help-PIApp", PIWK_normal,  400, 300, 100, 350)
{
dap = par;
piac = piacmd;
mNitem = 0;
SetMsg(77);

int bsx, bsy;
int tsx, tsy;
int spx, spy;
PIApplicationPrefCompSize(bsx, bsy);
spx = bsx/6;   spy = bsy/6;
tsx = 10*bsx+2*spx;  tsy = 7*bsy+3*spy;
SetSize(tsx,tsy);
hgrpom = new PIOptMenu(this, "hgrpoptmen", bsx*2.0, bsy, spx/2, spy);
hgrpom->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
hitemlist = new PIList(this, "hitemlist", bsx*2.0, tsy-3*spy-bsy, spx/2, 2*spy+bsy);
hitemlist->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
// hitemlist->SetBorderWidth(2);
mTxt = new PIText(this, "helptext", true, true, bsx*8.0, 6*bsy, bsx*2.0+1.5*spx, spy);
// mTxt->SetMutiLineMode(true);
mTxt->SetTextEditable(false);
mTxt->SetText("");
mTxt->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mLab = new PILabel(this, "helpitem", bsx*4, bsy, bsx*2.5+2*spx, tsy-spy-bsy);
mLab->SetBorderWidth(1);
mLab->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mLab->SetLabel("");
mBut = new PIButton(this, "Close", 70, bsx, bsy, tsx-bsx*1.5-spx, tsy-spy-bsy);
mBut->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
}

/* --Methode-- */
PIAHelpWind::~PIAHelpWind()
{
delete hgrpom;
delete hitemlist;
delete mTxt;
delete mLab;
delete mBut;
}

/* --Methode-- */
void PIAHelpWind::Process(PIMessage msg, PIMsgHandler* sender, void* /*data*/)
{
PIMessage um = UserMsg(msg);
if (((um == 77) && (ModMsg(msg) == PIMsg_Close)) || (um == 70) ) {
  Hide();
  return;
  }
else if ( (um >= 20000) && (sender == hgrpom)) {  // Selection de groupe de Help
  mTxt->SetText("");
  mLab->SetLabel("");
  piac->UpdateHelpList(this, um-20000);
}
else if ( (um > 100) && (sender == hitemlist) && (ModMsg(msg) == PIMsg_Select) ) {
  string s = hitemlist->GetSelectionStr();
  mTxt->SetText(piac->GetUsage(s));
  mLab->SetLabel(s);
  }  
}

/* --Methode-- */
void PIAHelpWind::Show()
{
hgrpom->SetValue(20000);   // Groupe All
mTxt->SetText("");
mLab->SetLabel("");
piac->UpdateHelpList(this, 0); 
PIWindow::Show();
}

// ------------------------------------------------------------
//         Bloc de commandes (Foreach, ...)    
//               Classe  PIACmdBloc    
// ------------------------------------------------------------

class PIACmdBloc {
public:
  enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat };

  PIACmdBloc(PIACmd* piac, PIACmdBloc* par, string& kw, vector<string>& args); 
  ~PIACmdBloc();
  inline PIACmdBloc*   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(PIACmdBloc* blk)  
    { blocs.push_back(blk); bloclineid.push_back(-blocs.size()); }
  PIACmdBloc*	Execute();
  inline int&   TestLevel()  { return testlevel; }
  inline int&   LoopLevel()  { return looplevel; }
  inline bool   CheckBloc() 
    { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)); }
  
protected:
  PIACmd* piacmd;
  PIACmdBloc* parent;
  bool blkok;        // true -> block OK
  BType typ;         // foreach , integer loop, float loop, test 
  string varname;
  vector<string> strlist;
  vector<string> lines;
  vector<PIACmdBloc *> 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-- */
PIACmdBloc::PIACmdBloc(PIACmd* piac, PIACmdBloc* par, string& kw, vector<string>& args)
{
piacmd = 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-- */
PIACmdBloc::~PIACmdBloc()
{
for(int k=0; k<blocs.size(); k++) delete blocs[k];
}

/* --Methode-- */
void PIACmdBloc::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-- */
PIACmdBloc* PIACmdBloc::Execute()
{
// cout << " DBG * PIACmdBloc::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;

if (typ == BT_ForeachList)   // foreach string loop
  for(k=0; k<strlist.size(); k++) {
    cmd = "set " + varname + " '" + strlist[k] + "'";
    piacmd->Interpret(cmd);
    for(kj=0; kj<bloclineid.size(); kj++) {
      kk = bloclineid[kj]; 
      if (kk > 0)  { 
	rcc = piacmd->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 (++k > 9999) {
      cout << ">>> Maximum PIACmdBloc loop limit (9999) -> break " << endl;
      break;
      }
    sprintf(buff, " %d", i);
    cmd = "set " + varname + buff;
    piacmd->Interpret(cmd);
    for(kj=0; kj<bloclineid.size(); kj++) {
      kk = bloclineid[kj]; 
      if (kk > 0)  { 
	rcc = piacmd->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 (++k > 9999) {
      cout << ">>> Maximum PIACmdBloc loop limit (9999) -> break " << endl;
      break;
      }
    sprintf(buff, " %g", f);
    cmd = "set " + varname + buff;
    piacmd->Interpret(cmd);
    for(kj=0; kj<bloclineid.size(); kj++) {
      kk = bloclineid[kj]; 
      if (kk > 0)  { 
	rcc = piacmd->Interpret(lines[kk-1]);
	if (rcc == 77766)  break;
      }
      else blocs[-kk-1]->Execute();
    }
    if (rcc == 77766)  break;
  }

return(parent); 
}

// ---------------------------------------------------------------
//                  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(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);
}

// ------------------------------------------------------------
//         Classe PIACmd
// ------------------------------------------------------------

static PIACmd* curpiacmd = NULL;
/* --Methode-- */
PIACmd::PIACmd(NamedObjMgr* omg, PIStdImgApp* app)
{
mObjMgr = omg; 
mImgApp = app;
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> ";
if (mImgApp) mImgApp->GetConsole()->SetPrompt(spromptmul);
curscript = NULL;

CmdBlks.push(NULL);
list<char> xtx;
TestsStack.push(xtx);
curtestresult = true;

cmdhgrp["All"] = 0;
cmdgrpid = 1;
cmdhgrp["PIACmd"] = 1;
helpwin = new PIAHelpWind(app, this);
helpwin->AddHelpGroup("All", 0);
helpwin->AddHelpGroup("PIACmd", 1);

string kw = "Interpreter";
string usage;
usage = ">>> (piacmd) 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 = "PIACmd";
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);

kw = "exitpiapp";
usage = "To end the piapp session (Interpreter's command)";
RegisterCommand(kw, usage, NULL, grp);

basexec = new PIABaseExecutor(this, omg, app);
fitexec = new PIAFitter(this, app);
pawexec = new PAWExecutor(this, app);
CxxExecutor * cxxe = new CxxExecutor(this, app);
cxxexec = cxxe;

ContModExecutor *cntxx = new ContModExecutor(this, app);//_OP_
cntexec = cntxx; //_OP_
FlowModExecutor *flwxx = new FlowModExecutor(this, app);//_OP_
flwexec = flwxx; //_OP_

cxxoptwin = new  CxxOptionWind(app, cxxe);
cxxexwin  = new  CxxExecWind(app, cxxe);

AddInterpreter(this);
curcmdi = this;
}

/* --Methode-- */
PIACmd::~PIACmd()
{
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; 
 
delete helpwin;
delete cxxexwin;
delete cxxoptwin;
if (curpiacmd == this)  curpiacmd = NULL;
delete basexec;
delete fitexec;
delete pawexec;
delete cxxexec;
}

/* --Methode-- */
PIACmd* PIACmd::GetInterpreter()
{
return(curpiacmd);
}

/* --Methode-- */
string PIACmd::Name()
{
return("piacmd");
}

/* --Methode-- */
void PIACmd::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 PIACmd::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 PIACmd::CheckHelpGrp(string& grp)
{
int gid=0;
CmdHGroup::iterator it = cmdhgrp.find(grp);
if (it == cmdhgrp.end()) {
  cmdgrpid++;   gid = cmdgrpid;
  cmdhgrp[grp] = gid;
  helpwin->AddHelpGroup(grp.c_str(), gid);
  }
else gid = (*it).second;
return(gid);
}

/* --Methode-- */
void PIACmd::UpdateHelpList(PIAHelpWind* hw, int gid)
{
helpwin->ClearHelpList();
CmdExmap::iterator it;
for(it = helpexmap.begin(); it != helpexmap.end(); it++) {
  if ( (gid != 0) && ((*it).second.group != gid) ) continue;
  helpwin->AddHelpItem((*it).first.c_str());
  }
for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
  if ( (gid != 0) && ((*it).second.group != gid) ) continue;
  helpwin->AddHelpItem((*it).first.c_str());
  }
}

/* --Methode-- */
void PIACmd::LoadModule(string& fnameso, string& name)
{
PDynLinkMgr * dynlink = new PDynLinkMgr(fnameso, false);
if (dynlink == NULL) {
  cerr << "PIACmd/LoadModule_Error: Pb opening SO " << fnameso << endl;
  return;
  }
string fname = name + "_init";
DlModuleInitEndFunction finit = dynlink->GetFunction(fname);
if (!finit) {
  cerr << "PIACmd/LoadModule_Error: Pb linking " << fname << endl;
  return;
  }
cout << "PIACmd/LoadModule_Info: Initialisation module" << name 
     << "  " << fname << "() ..." << endl;
finit();
modmap[name] = dynlink;
return;
}

/* --Methode-- */
void PIACmd::AddInterpreter(CmdInterpreter * cl)
{
if (!cl) return;
interpmap[cl->Name()] = cl;}

/* --Methode-- */
void PIACmd::SelInterpreter(string& name)
{
InterpMap::iterator it = interpmap.find(name);
if (it == interpmap.end())   return;
curcmdi = (*it).second;
}



/* Fonction */
static string GetStringFrStdin(PIACmd* piac)
{
PIStdImgApp* piapp = piac->GetImgApp();
if (piapp) {
  PIBaseWdg* wdg = piapp->CurrentBaseWdg();
  if (wdg)  wdg->Refresh();
#ifndef __mac__
  /* On vide le buffer X-Window */
  XSync(PIXDisplay(),False);
#endif
}
char buff[128];
fgets(buff, 128, stdin);
buff[127] = '\0';
return((string)buff);
}

/* --Methode-- */
int PIACmd::Interpret(string& s)
{
int rc = 0;
NamedObjMgr omg;
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 = mImgApp->GetConsole()->GetPrompt();
    mImgApp->GetConsole()->SetPrompt("...? ");
    mulinefg = true;
  }
  return(0);
}

if (mulinefg) {  // Il y avait des lignes suite
  s = mulinecmd + s;
  mulinecmd = "";
  mulinefg = false;
  mImgApp->GetConsole()->SetPrompt(spromptmul);
}

// Removing leading blanks
size_t p,q;

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 << "PIACmd::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 << "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
  if ( (kw == "for") || (kw == "foreach")) felevel++;
  else if (kw == "end") felevel--;
  if (felevel == 0) { // Il faut executer le bloc
    PIACmdBloc* curb = CmdBlks.top();
    CmdBlks.top() = curb->Parent();
    mImgApp->GetConsole()->SetPrompt("Cmd> ");
    if (!curb->CheckBloc()) {
      cerr << "PIACmd::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 PIACmdBloc and testresult on the stack
      CmdBlks.push(NULL);
      list<char> xtx;
      TestsStack.push(xtx);
      curb->Execute();
      // And PIACmdBloc 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 << "PIACmd::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 << "PIACmd::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;
      mImgApp->GetConsole()->SetPrompt(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;
    mImgApp->GetConsole()->SetPrompt(npr);
    return(0);
  }
} 
else if ((kw == "else") || (kw == "endif")) {
  cerr << "PIACmd::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 ;
// Execution de code C++

if (kw == "@@") {
  CxxExecutor * cxxe = dynamic_cast<CxxExecutor *>(cxxexec);
  if (cxxe == NULL) {
    cerr << "PIACmd::Interpret() - BUG !!! Not a CxxExecutor " << endl;
    return(99);
  }
  return(cxxe->ExecuteCXX(s.substr(2)));
}


rcs = SubstituteVars(s, s2);
if (rcs) { 
  cerr << "PIACmd::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;
  PIACmdBloc* bloc = new PIACmdBloc(this, CmdBlks.top(), kw, tokens);
  if (!bloc->CheckOK()) {
    cerr << "PIACmd::Interpret() for/foreach syntax Error ! " << endl;
    delete bloc;
    return(1);
    }
  felevel++;
  if (CmdBlks.top())  CmdBlks.top()->AddBloc(bloc);
  else  mImgApp->GetConsole()->SetPrompt("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 << "PIACmd::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> ";
  mImgApp->GetConsole()->SetPrompt(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 << "PIACmd::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 PIACmdScript(this, tokens[0], tokens[1]);
    mImgApp->GetConsole()->SetPrompt("Script...> ");
    return(0);
  }
  else {
    cerr << "PIACmd::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 << "PIACmd::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 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);
}

/* --Methode-- */
int PIACmd::SubstituteVars(string & s, string & s2)
//  Variable substitution  
{
NamedObjMgr& omg = *mObjMgr;

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 PIACmd::GetVar(string & vn, string & vv)
{
NamedObjMgr& omg = *mObjMgr;
if (vn.length() < 1) {
  cerr << " PIACmd::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 << " PIACmd::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 << " PIACmd::SubstituteVar/Error: ArgsStack empty ! " 
	 << " ($" << vn << ")" << endl;
    vv = ""; return(false);
  }
  if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) {
    cerr << " PIACmd::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 (!omg.HasVar(vn) ) {
    cerr << " PIACmd::SubstituteVarError: Undefined variable " 
	 << vn << " ! " << endl;
    vv = "";  return(false);
  }
  vn = omg.GetVar(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 ( (!omg.HasVar(vn)) )  {
    cerr << " PIACmd::SubstituteVarError: Undefined variable " 
	 << vn << " ! " << endl;
    vv = "";  return(false);
  }
  vv = omg.GetVar(vn);  return(true);
}

return(false);
}

/* --Methode-- */
int PIACmd::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 << "PIACmd::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 << "PIACmd::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 << "PIACmd::EvalRPNExpr/PrintStack: Empty stack " << endl;
  else {
    int k = 0;
    cout << "PIACmd::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 PIACmd::EvalRPNExpr(vector<string> & args, string & line)
{
  NamedObjMgr& omg = *mObjMgr;
  
  if (args.size() < 2) { 
    cerr << "PIACmd::EvalRPNExpr: syntax error / missing arguments " << line << endl; 
    return(1);
  }
  else if (args.size() == 2) { 
    omg.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 << "PIACmd::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 << "PIACmd::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 << "PIACmd::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;
  omg.SetVar(args[0], res);
  return(0);
}

/* --Methode-- */
void PIACmd::PushStack(vector<string>& args)
{
  // We push the argument list (args) on the stack
  ArgsStack.push(args);
  // We push also PIACmdBloc and testresult on the stack
  CmdBlks.push(NULL);
  list<char> xtx;
  TestsStack.push(xtx);

}

/* --Methode-- */
void PIACmd::PopStack(bool psta)
{
  // We remove the argument list (args) from the stack
  if (psta) ArgsStack.pop();
  // And PIACmdBloc and TestResult from the corresponding stacks
  PIACmdBloc* curb = CmdBlks.top();
  while (curb != NULL) {
    PIACmdBloc* parb = curb->Parent();
    delete curb;  curb = parb;
  }
  CmdBlks.pop();
  TestsStack.pop();
}

/* --Methode-- */
int PIACmd::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
{
int rc = 0;
NamedObjMgr omg;

// >>>>>>>>>>> Commande d'interpreteur
if (kw == "helpwindow") ShowHelpWindow();
else if (kw == "help") {
  if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl;
  else {  
    string kwh = "piacmd";
    cout << GetUsage(kwh) << endl;
    }
  }

else if (kw == "set") {
  if (tokens.size() < 2) { cout << "PIACmd::Interpret() Usage: set varname string" << endl;  return(0); }
  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
    cerr << "PIACmd::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] );
  omg.SetVar(tokens[0], tokens[1]);
  }

else if (kw == "getvar") {
  if (tokens.size() < 2) { cout << "PIACmd::Interpret() Usage: getvar newvarname varname" << endl;  return(0); }
  if (!omg.HasVar(tokens[1])) {
    cerr << "Error - No " << tokens[1] << " Variable " << endl;
    return(0);
    } 
  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
    cerr << "PIACmd::Interpret()/Error Variable name should start with alphabetic" << endl;
    return(0);
    }
  omg.SetVar(tokens[0], omg.GetVar(tokens[1]) );
  }

else if (kw == "alias") {
  if (tokens.size() < 2) { cout << "PIACmd::Interpret() Usage: alias aliasname string" << endl;  return(0); }
  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
    cerr << "PIACmd::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 == "setol") {
  if (tokens.size() < 2) { cout << "PIACmd::Interpret() Usage: setol varname objnamepattern" << endl;  return(0); }
  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
    cerr << "PIACmd::Interpret()/Error Variable name should start with alphabetic" << endl;
    return(0);
    }
  vector<string> ol;
  mObjMgr->GetObjList(tokens[1], ol);
  string vol; 
  if (ol.size() < 1) vol = "";
  else { 
     vol = ol[0]; 
    for (int kk=1; kk<ol.size(); kk++)  vol += (' ' + ol[kk]);
    }
  omg.SetVar(tokens[0], vol);
  }
else if (kw == "unset") {
  if (tokens.size() < 1) { cout << "PIACmd::Interpret() Usage: unset varname" << endl;  return(0); }
  if (omg.HasVar(tokens[0])) omg.DeleteVar(tokens[0]) ;
  else cerr << "PIACmd::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 << "PIACmd::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 << "PIACmd::Interpret() Usage: readstdin varname" << endl;  return(0); }
  if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
    cerr << "PIACmd::Interpret()/Error Variable name should start with alphabetic" << endl;
    return(0);
    }
  mImgApp->GetConsole()->AddStr(">>> Reading From StdIn \n", PIVA_Magenta);
  cout << tokens[0] << " ? " << endl;
  omg.SetVar(tokens[0], GetStringFrStdin(this) );
  }

else if (kw == "listvars") {
  cout << "PIACmd::Interpret()  Variable List , VarName = Value \n";
  DVList& varlist = omg.GetVarList();
  DVList::ValList::const_iterator it;
  string value;
  for(it = varlist.Begin(); it != varlist.End(); it++) {
#ifdef SANS_EVOLPLANCK
    MuTyV mtv = (*it).second;
    value = (string)(mtv);
#else
    value = (string)((*it).second.elval);
#endif
    cout << (*it).first << " = " <<  value << "\n";
    }
  cout << endl;
  }
else if (kw == "listalias") {
  cout << "PIACmd::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 << "---- PIACmd::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 << "---- 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; }
else if (kw == "timingon") { 
  cout << "PIACmd::Interpret()  -> Timing ON mode " << endl; 
  if (gltimer)   delete gltimer;   gltimer = new Timer("PIA-CmdInterpreter ");   timing = true; 
  }
else if (kw == "timingoff") { 
  cout << "PIACmd::Interpret()  -> Timing OFF mode " << endl; 
  if (gltimer)  delete gltimer;  gltimer = NULL;  timing = false; 
  }
else if (kw == "exec") {
  if (tokens.size() < 1) { cout << "PIACmd::Interpret() Usage: exec filename" << endl;  return(0); }
  ExecFile(tokens[0], tokens);
  }
else if (kw == "autoiniranf") { 
  Auto_Ini_Ranf(1);
  return(0);
}
// ----> Sortie d'application
else if (kw == "exitpiapp") {
  mImgApp->Stop();
  return(0);
}
else if (kw == "shell") {
  if (tokens.size() < 1) { cout << "PIACmd::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<<"PIACmd::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 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);
LineToWords(line, kw, tokens, toks, qw);
return(ExecuteCommand(kw, tokens, toks));  
}

/* --Methode-- */
int PIACmd::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 PIACmd::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 << "PIACmd::Exec(): Error opening file " << file << endl;
    file += ".pic";
    cout << "                Trying file " << file << endl;
    fip = fopen(file.c_str(),"r");
    }
  }

if(fip == NULL) {
  cerr << "PIACmd::Exec() Error opening file " << file << endl;
  hist << "##! PIACmd::Exec() Error opening file " << file << endl;
  return(0);
  }

// hist << "### Executing commands from " << file << endl;

PushStack(args);
if (trace) { 
  mImgApp->GetConsole()->AddStr("### Executing commands from ", PIVA_Magenta);
  mImgApp->GetConsole()->AddStr(file.c_str(), PIVA_Magenta);
  mImgApp->GetConsole()->AddStr("\n", PIVA_Magenta);
  }

bool ohv = histon;
histon = false; 
while (fgets(line_buff,511,fip) != NULL)
  {
  if (trace) mImgApp->GetConsole()->AddStr(line_buff, PIVA_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) { 
  mImgApp->GetConsole()->AddStr("### End of Exec( ", PIVA_Magenta);
  mImgApp->GetConsole()->AddStr(file.c_str(), PIVA_Magenta);
  mImgApp->GetConsole()->AddStr(" ) \n", PIVA_Magenta);
  }

PopStack(true);

return(0);
}

/* --Methode-- */
int PIACmd::CShellExecute(string cmd)
{
 if(cmd.size()<=0) return -1;

 NamedObjMgr omg;
 string fname = omg.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 << "PIACmd/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& PIACmd::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);
 
}

/* --Methode-- */
void PIACmd::ShowHelpWindow()
{
helpwin->Show();
}

/* --Methode-- */
void PIACmd::ShowCxxOptionWindow()
{
cxxoptwin->Show();
}

/* --Methode-- */
void PIACmd::ShowCxxExecWindow()
{
cxxexwin->Show();
}

/*  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 PIACmd::HelptoLaTeX(string const & fname)
{
FILE *fip;
if ((fip = fopen(fname.c_str(), "w")) == NULL)   { 
  cout << "PIACmd::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;
}



