source: Sophya/trunk/SophyaLib/SysTools/commander.cc@ 2473

Last change on this file since 2473 was 2473, checked in by ansari, 22 years ago

Initialisation numero help-gid + declarations virtual pour les methodes de Commander - Reza 4 Dec 2003

File size: 54.2 KB
Line 
1#include "commander.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <math.h>
6
7#include "strutil.h"
8#include "strutilxx.h"
9#include "srandgen.h"
10
11
12// ------------------------------------------------------------
13// Bloc de commandes (Foreach, ...)
14// Classe CommanderBloc
15// ------------------------------------------------------------
16/*!
17 \class SOPHYA::CommanderBloc
18 \ingroup SysTools
19 Class for internal use by SOPHYA::Commander to handle loops
20*/
21class CommanderBloc {
22public:
23 enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat };
24
25 CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args);
26 ~CommanderBloc();
27 inline CommanderBloc* Parent() { return(parent); }
28 inline bool CheckOK() { return blkok; }
29 inline void AddLine(string& line)
30 { lines.push_back(line); bloclineid.push_back(lines.size()); }
31 void AddLine(string& line, string& kw);
32 inline void AddBloc(CommanderBloc* blk)
33 { blocs.push_back(blk); bloclineid.push_back(-blocs.size()); }
34 CommanderBloc* Execute();
35 inline int& TestLevel() { return testlevel; }
36 inline int& LoopLevel() { return looplevel; }
37 inline bool CheckBloc()
38 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)); }
39
40protected:
41 Commander* _commander;
42 CommanderBloc* parent;
43 bool blkok; // true -> block OK
44 BType typ; // foreach , integer loop, float loop, test
45 string varname;
46 vector<string> strlist;
47 vector<string> lines;
48 vector<CommanderBloc *> blocs;
49 vector<int> bloclineid;
50 int i1,i2,di;
51 float f1,f2,df;
52 int testlevel; // niveau d'imbrication des if
53 int looplevel; // niveau d'imbrication des for/foreach
54 bool scrdef; // true -> commande defscript ds for/foreach
55};
56
57/* --Methode-- */
58CommanderBloc::CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args)
59{
60_commander = piac;
61parent = par;
62blkok = false;
63typ = BT_None;
64i1 = 0; i2 = -1; di = 1;
65f1 = 0.; f2 = -1.; df = 1.;
66testlevel = looplevel = 0;
67scrdef = false;
68
69if ((args.size() < 2) || !isalpha((int)args[0][0]) ) return;
70if ((kw != "foreach") && (kw != "for")) return;
71varname = args[0]; // $CHECK$ Variable name should be checked
72//if (isalpha((int)args[1][0]) ) { This is a foreach bloc with string list
73if (kw == "foreach" ) { // This is a foreach bloc with string list
74 if ((args[1] != "(") || (args[args.size()-1] != ")") ) return;
75 for(int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
76 typ = BT_ForeachList;
77 blkok = true;
78 }
79else { // This is an integer or float loop
80 size_t l = args[1].length();
81 size_t p = args[1].find(':');
82 size_t pp = args[1].find('.');
83 bool fl = (pp < l) ? true : false; // Float loop or integer loop
84 if (p >= l) return; // Syntaxe error
85 string a1 = args[1].substr(0, p);
86 string aa = args[1].substr(p+1);
87 p = aa.find(':');
88 string a2, a3;
89 bool hasa3 = false;
90 if (p < aa.length() ) {
91 a2 = aa.substr(0,p);
92 a3 = aa.substr(p+1);
93 hasa3 = true;
94 }
95 else a2 = aa;
96 if (fl) {
97 typ = BT_ForeachFloat;
98 blkok = true;
99 f1 = atof(a1.c_str());
100 f2 = atof(a2.c_str());
101 if (hasa3) df = atof(a3.c_str());
102 else df = 1.;
103 }
104 else {
105 typ = BT_ForeachInt;
106 blkok = true;
107 i1 = atoi(a1.c_str());
108 i2 = atoi(a2.c_str());
109 if (hasa3) di = atoi(a3.c_str());
110 else di = 1;
111 }
112 }
113}
114
115/* --Methode-- */
116CommanderBloc::~CommanderBloc()
117{
118for(int k=0; k<blocs.size(); k++) delete blocs[k];
119}
120
121/* --Methode-- */
122void CommanderBloc::AddLine(string& line, string& kw)
123{
124 AddLine(line);
125 if (kw == "if") testlevel++;
126 else if (kw == "endif") testlevel--;
127 else if ((kw == "for") || (kw == "foreach")) looplevel++;
128 else if (kw == "end") looplevel--;
129 else if (kw == "defscript") scrdef = true;
130}
131
132/* --Methode-- */
133CommanderBloc* CommanderBloc::Execute()
134{
135// cout << " DBG * CommanderBloc::Execute() " << typ << " - " << bloclineid.size() <<
136// " I1,I2=" << i1 << " , " << i2 << " , " << di << endl;
137string cmd;
138int k=0;
139int kj=0;
140int kk=0;
141char buff[32];
142int rcc = 0;
143
144int mxloop = _commander->GetMaxLoopLimit();
145
146if (typ == BT_ForeachList) // foreach string loop
147 for(k=0; k<strlist.size(); k++) {
148 cmd = "set " + varname + " '" + strlist[k] + "'";
149 _commander->Interpret(cmd);
150 for(kj=0; kj<bloclineid.size(); kj++) {
151 kk = bloclineid[kj];
152 if (kk > 0) {
153 rcc = _commander->Interpret(lines[kk-1]);
154 if (rcc == 77766) break;
155 }
156 else blocs[-kk-1]->Execute();
157 }
158 if (rcc == 77766) break;
159 }
160else if (typ == BT_ForeachInt) // Integer loop
161 for(int i=i1; i<i2; i+=di) {
162 k++;
163 if ((mxloop>0) && (k > mxloop)) {
164 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
165 break;
166 }
167 sprintf(buff, " %d", i);
168 cmd = "set " + varname + buff;
169 _commander->Interpret(cmd);
170 for(kj=0; kj<bloclineid.size(); kj++) {
171 kk = bloclineid[kj];
172 if (kk > 0) {
173 rcc = _commander->Interpret(lines[kk-1]);
174 if (rcc == 77766) break;
175 }
176 else blocs[-kk-1]->Execute();
177 }
178 if (rcc == 77766) break;
179 }
180else if (typ == BT_ForeachFloat) // float loop
181 for(float f=f1; f<f2; f+=df) {
182 k++;
183 if ((mxloop>0) && (k > mxloop)) {
184 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
185 break;
186 }
187 sprintf(buff, " %g", f);
188 cmd = "set " + varname + buff;
189 _commander->Interpret(cmd);
190 for(kj=0; kj<bloclineid.size(); kj++) {
191 kk = bloclineid[kj];
192 if (kk > 0) {
193 rcc = _commander->Interpret(lines[kk-1]);
194 if (rcc == 77766) break;
195 }
196 else blocs[-kk-1]->Execute();
197 }
198 if (rcc == 77766) break;
199 }
200
201return(parent);
202}
203
204// ---------------------------------------------------------------
205// Classe CommanderScript
206// Definition et execution d'un script de Commander
207// script : Une liste de commande Commander - Lors de l'execution,
208// les variables-argument $# $0 $1 sont definies.
209// ---------------------------------------------------------------
210
211/*!
212 \class SOPHYA::CommanderScript
213 \ingroup SysTools
214 Class for internal use by SOPHYA::Commander to handle functions
215 or scripts
216*/
217
218class CommanderScript {
219public:
220 CommanderScript(Commander* piac, string const& name, string const& comm);
221 virtual ~CommanderScript();
222
223 void AddLine(string& line, string& kw);
224 virtual int Execute(vector<string>& args);
225
226 inline string& Name() { return mName; }
227 inline string& Comment() { return mComm; }
228 inline int& TestLevel() { return testlevel; }
229 inline int& LoopLevel() { return looplevel; }
230 inline bool CheckScript()
231 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)&&fgok); }
232
233protected:
234 Commander* _commander;
235 string mName;
236 string mComm;
237 vector<string> lines;
238 int testlevel; // niveau d'imbrication des if
239 int looplevel; // niveau d'imbrication des for/foreach
240 bool scrdef; // true -> commande defscript ds for/foreach
241 bool fgok; // Script name OK
242
243};
244
245/* --Methode-- */
246CommanderScript::CommanderScript(Commander* piac, string const& name,
247 string const& comm)
248{
249_commander = piac;
250testlevel = looplevel = 0;
251scrdef = false;
252mName = name;
253if (!isalpha(name[0])) fgok = false;
254else fgok = true;
255mComm = comm;
256}
257
258/* --Methode-- */
259CommanderScript::~CommanderScript()
260{
261}
262
263/* --Methode-- */
264void CommanderScript::AddLine(string& line, string& kw)
265{
266 if (kw == "if") testlevel++;
267 else if (kw == "endif") testlevel--;
268 else if ((kw == "for") || (kw == "foreach")) looplevel++;
269 else if (kw == "end") looplevel--;
270 else if (kw == "defscript") scrdef = true;
271 lines.push_back(line);
272}
273
274/* --Methode-- */
275int CommanderScript::Execute(vector<string>& args)
276{
277 if (!CheckScript()) return(-1);
278 cout << " CommanderScript::Execute() - Executing script " << Name() << endl;
279 for(int k=0; k<lines.size(); k++) {
280 if (_commander->Interpret(lines[k]) == 77777) break;
281 }
282 return(0);
283}
284
285// ------------------------------------------------------------
286// Classe Commander
287// ------------------------------------------------------------
288typedef void (* DlModuleInitEndFunction) ();
289
290/*!
291 \class SOPHYA::Commander
292 \ingroup SysTools
293 Simple command interpreter with c-shell like syntax and dynamic
294 load capabilities. Can be used to add scripting capabilities
295 to applications
296*/
297
298#define _MAGENTA_ 1
299
300static Commander* cur_commander = NULL;
301/* --Methode-- */
302Commander::Commander()
303{
304system("cp history.pic hisold.pic");
305hist.open("history.pic");
306histon = true;
307trace = false; timing = false;
308gltimer = NULL;
309felevel = 0;
310
311mulinecmd = "";
312mulinefg = false;
313spromptmul = "Cmd> ";
314SetCurrentPrompt(spromptmul);
315curscript = NULL;
316
317CmdBlks.push(NULL);
318list<char> xtx;
319TestsStack.push(xtx);
320curtestresult = true;
321
322// Numero de help-groupe courant - Le premier groupe ajoute aura un gid = 1
323// gid = 0 n'existe pas : c'est le groupe de toutes les commandes
324cmdgrpid = 0;
325
326string grp = "Commander";
327string gdesc = "Basic (generic) interpreter (class SOPHYA::Commander) builtin commands";
328AddHelpGroup(grp, gdesc);
329
330string kw = "Commander";
331string usage;
332usage = ">>> (Commander) Interpreter's keywords : \n";
333usage += " > set varname string # To set a variable, $varname \n";
334usage += " > get newvarname varname # To set a newvariable, equal to $varname \n";
335usage += " > setol varname patt # Fills varname with object list \n";
336usage += " > unset varname # clear variable definition \n";
337usage += " > rpneval varname RPNExpression # Reverse Polish Notation evaluation \n";
338usage += " > varname = 'string string ...' # To set a variable, $varname \n";
339usage += " > varname = RPNExpression # RPN evaluation / result -> varname \n";
340usage += " > echo string # output string \n";
341usage += " > echo2file filename string # Append the string to the specified file \n";
342usage += " > alias name string # define a command alias \n";
343usage += " > readstdin varname # reads a line from stdin into $varname \n";
344usage += " > foreach varname ( string-list ) # Loop \n";
345usage += " > for varname i1:i2[:di] # Integer loop \n";
346usage += " > for varname f1:f2[:df] # Float loop \n";
347usage += " > end # end loops \n";
348usage += " > if ( test ) then # Conditional test : a == != < > <= >= b \n";
349usage += " > else # Conditional \n";
350usage += " > endif # End of conditional if bloc \n";
351usage += " > break # Delete (clears) all test and loop blocs \n";
352usage += " > return # Stops command execution from a file \n";
353usage += " > defscript endscript # Command script definition \n";
354usage += " > listvars # List of variable names and values \n";
355usage += " > listalias # List of alias names and values \n";
356usage += " > listcommands # List of all known commands \n";
357usage += " > listscripts # List of all known scripts \n";
358usage += " > clearcript # Clear a script definition \n";
359usage += " > exec filename # Execute commands from file \n";
360usage += " > help <command_name> # <command_name> usage info \n";
361usage += " > timingon timingoff traceon traceoff \n";
362RegisterHelp(kw, usage, grp);
363
364kw = "RPNEvaluator";
365usage = " Reverse Polish Notation (HP calculator like) expression evaluation \n";
366usage += " >> Stack: \n";
367usage += " ... (4) (3) z=(2) y=(1) x=(0)=Stack.Top() \n";
368usage += " >> Examples: \n";
369usage += " - sin(PI/6): pi 6 / sin \n";
370usage += " - 1*2*...*5: 1 2 3 4 5 product \n";
371usage += " - x=x+y: x = $x $y * \n";
372usage += " >>> Stack operations : \n";
373usage += " print x<>y pop push (duplicate x) \n";
374usage += " >>> Constants (Cst pushed to stack): \n";
375usage += " pi e \n";
376usage += " >>> Arithmetic operators (x,y) --> x@y \n";
377usage += " + - * / % ( (int)y % (int)x )\n";
378usage += " >>> F(X): x --> F(x) \n";
379usage += " chs sqrt sq log log10 exp \n";
380usage += " fabs floor ceil \n";
381usage += " cos sin tan acos asin atan deg2rad rad2deg \n";
382usage += " >>> F(X,Y): (x,y) --> F(x,y) \n";
383usage += " pow atan2 \n";
384usage += " >>> F(): random number generators \n";
385usage += " rand (flat 0..1) norand (normal/gaussian) \n";
386usage += " >>> Stack sum/product/mean/sigma/sigma^2 \n";
387usage += " sum product mean sigma sigma2 sigmean (y->sigma x->mean) \n";
388RegisterHelp(kw, usage, grp);
389
390kw = "autoiniranf";
391usage = "> Automatic random number generator initialisation\n";
392usage += " by Auto_Ini_Ranf(int lp) \n";
393usage += " Usage: autoiniranf";
394RegisterCommand(kw, usage, NULL, grp);
395
396kw = "shell execute";
397usage = "> shell command_string # Execute shell command\n";
398usage += "> cshell command_string # Execute cshell command\n";
399usage += "---Examples:\n";
400usage += " > shell ls\n";
401usage += " > cshell echo '$LD_LIBRARY_PATH'; map2cl -h; ls\n";
402usage += " > shell myfile.csh [arg1] [arg2] [...]\n";
403usage += " (where the first line of \"myfile.csh\" is \"#!/bin/csh\")\n";
404RegisterCommand(kw, usage, NULL, grp);
405
406
407AddInterpreter(this);
408curcmdi = this;
409}
410
411/* --Methode-- */
412Commander::~Commander()
413{
414hist.close();
415if (gltimer) { delete gltimer; gltimer = NULL; }
416Modmap::iterator it;
417for(it = modmap.begin(); it != modmap.end(); it++) {
418 string name = (*it).first + "_end";
419 DlModuleInitEndFunction fend = (*it).second->GetFunction(name);
420 if (fend) fend();
421 delete (*it).second;
422 }
423
424for(ScriptList::iterator sit = mScripts.begin();
425 sit != mScripts.end(); sit++) delete (*sit).second;
426
427if (cur_commander == this) cur_commander = NULL;
428}
429
430/* --Methode-- */
431Commander* Commander::GetInterpreter()
432{
433return(cur_commander);
434}
435
436/* --Methode-- */
437string Commander::Name()
438{
439return("Commander");
440}
441
442/* --Methode-- */
443void Commander::AddHelpGroup(string& grp, string& desc)
444{
445 int gid;
446 CheckHelpGrp(grp, gid, desc);
447}
448
449/* --Methode-- */
450void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string& grp)
451{
452if (!ce) {
453 RegisterHelp(keyw, usage, grp);
454 return;
455 }
456int gid;
457CheckHelpGrp(grp,gid);
458cmdex cme;
459cme.group = gid;
460cme.us = usage;
461cme.cex = ce;
462cmdexmap[keyw] = cme;
463}
464
465/* --Methode-- */
466void Commander::RegisterHelp(string& keyw, string& usage, string& grp)
467{
468int gid;
469CheckHelpGrp(grp,gid);
470cmdex cme;
471cme.group = gid;
472cme.us = usage;
473cme.cex = NULL;
474helpexmap[keyw] = cme;
475}
476
477/* --Methode-- */
478bool Commander::CheckHelpGrp(string& grp, int& gid, string& desc)
479{
480gid = 0;
481CmdHGroup::iterator it = cmdhgrp.find(grp);
482if (it == cmdhgrp.end()) {
483 cmdgrpid++; gid = cmdgrpid;
484 hgrpst hgs; hgs.gid = gid; hgs.desc = desc;
485 cmdhgrp[grp] = hgs;
486 return true;
487 }
488else {
489 if (desc.length() > 0) (*it).second.desc = desc;
490 gid = (*it).second.gid;
491 return false;
492}
493}
494
495
496/* --Methode-- */
497void Commander::LoadModule(string& fnameso, string& name)
498{
499PDynLinkMgr * dynlink = new PDynLinkMgr(fnameso, false);
500if (dynlink == NULL) {
501 cerr << "Commander/LoadModule_Error: Pb opening SO " << fnameso << endl;
502 return;
503 }
504string fname = name + "_init";
505DlModuleInitEndFunction finit = dynlink->GetFunction(fname);
506if (!finit) {
507 cerr << "Commander/LoadModule_Error: Pb linking " << fname << endl;
508 return;
509 }
510cout << "Commander/LoadModule_Info: Initialisation module" << name
511 << " " << fname << "() ..." << endl;
512finit();
513modmap[name] = dynlink;
514return;
515}
516
517/* --Methode-- */
518void Commander::AddInterpreter(CmdInterpreter * cl)
519{
520if (!cl) return;
521interpmap[cl->Name()] = cl;}
522
523/* --Methode-- */
524void Commander::SelInterpreter(string& name)
525{
526InterpMap::iterator it = interpmap.find(name);
527if (it == interpmap.end()) return;
528curcmdi = (*it).second;
529}
530
531
532
533/* Fonction */
534static string GetStringFrStdin(Commander* piac)
535{
536char buff[128];
537fgets(buff, 128, stdin);
538buff[127] = '\0';
539return((string)buff);
540}
541
542/* --Methode-- */
543int Commander::Interpret(string& s)
544{
545int rc = 0;
546ScriptList::iterator sit;
547
548// On saute de commandes vides
549size_t l;
550l = s.length();
551if (!mulinefg && (l < 1)) return(0);
552
553// On enregistre les commandes
554if (histon) hist << s << endl;
555
556if (s[0] == '#') return(0); // si c'est un commentaire
557
558// Logique de gestion des lignes suite
559// un \ en derniere position indique la presence d'une ligne suite
560size_t lnb = s.find_last_not_of(' ');
561if (s[lnb] == '\\' ) { // Lignes suite ...
562 mulinecmd += s.substr(0,lnb);
563 if (!mulinefg) {
564 spromptmul = GetCurrentPrompt();
565 SetCurrentPrompt("...? ");
566 mulinefg = true;
567 }
568 return(0);
569}
570
571if (mulinefg) { // Il y avait des lignes suite
572 s = mulinecmd + s;
573 l = s.length();
574 mulinecmd = "";
575 mulinefg = false;
576 SetCurrentPrompt(spromptmul);
577}
578
579// Removing leading blanks
580size_t p,q;
581
582// On enleve le dernier caractere, si celui-ci est \n
583if (s[l-1] == '\n') s[l-1] = '\0';
584p=s.find_first_not_of(" \t");
585if (p < l) s = s.substr(p);
586// >>>> Substitution d'alias (1er mot)
587CmdStrList::iterator it;
588p = 0;
589q = s.find_first_of(" \t");
590l = s.length();
591string w1 = (q < l) ? s.substr(p,q-p) : s.substr(p);
592it = mAliases.find(w1);
593if (it != mAliases.end()) {
594 s = (q < l) ? ((*it).second + s.substr(q)) : (*it).second ;
595 l = s.length();
596 p=s.find_first_not_of(" \t");
597 if (p < l) s = s.substr(p);
598 p = 0;
599 q = s.find_first_of(" ");
600 }
601
602// >>>> Separating keyword
603string toks,kw;
604if (q < l)
605 { kw = s.substr(p,q-p); toks = s.substr(q, l-q); }
606else { kw = s.substr(p,l-p); toks = ""; }
607
608// les mot-cle end else endif doivent etre le seul mot de la ligne
609if ( (kw == "end") || (kw == "else") || (kw == "endif") || (kw == "endscript") ) {
610 size_t ltk = toks.length();
611 if (toks.find_first_not_of(" \t") < ltk) {
612 cerr << "Commander::Interpret()/syntax error near end else endif endscript \n"
613 << "line: " << s << endl;
614 return(1);
615 }
616}
617
618// On verifie si on est en train de definir un script
619if (curscript) {
620 if (kw == "endscript") {
621 if (curscript->CheckScript()) {
622 sit = mScripts.find(curscript->Name());
623 if (sit != mScripts.end()) {
624 cout << "Commander::Interpret() replacing script "
625 << curscript->Name() << endl;
626 CommanderScript* scr = mScripts[curscript->Name()];
627 mScripts.erase(sit);
628 delete scr;
629 }
630 cout << "Commander::Interpret() Script " << curscript->Name()
631 << " defined successfully" << endl;
632 mScripts[curscript->Name()] = curscript;
633 SetCurrentPrompt("Cmd> ");
634 curscript = NULL;
635 return(0);
636 }
637 else {
638 cout << "Commander::Interpret() Error in Script " << curscript->Name()
639 << " definition " << endl;
640 SetCurrentPrompt("Cmd> ");
641 curscript = NULL;
642 return(2);
643 }
644 }
645 else curscript->AddLine(s, kw);
646 return(0);
647}
648// On verifie si nous sommes dans un bloc (for , foreach)
649if (CmdBlks.top() != NULL) { // On est dans un bloc
650 if ( (kw == "for") || (kw == "foreach")) felevel++;
651 else if (kw == "end") felevel--;
652 if (felevel == 0) { // Il faut executer le bloc
653 CommanderBloc* curb = CmdBlks.top();
654 CmdBlks.top() = curb->Parent();
655 SetCurrentPrompt("Cmd> ");
656 if (!curb->CheckBloc()) {
657 cerr << "Commander::Interpret()/syntax error - unbalenced if ... endif"
658 << " within for/foreach bloc ! " << endl;
659 delete curb;
660 return(2);
661 }
662 // cout << " *DBG* Executing bloc " << endl;
663 bool ohv = histon;
664 histon = false;
665 if (curtestresult) {
666 // We push also CommanderBloc and testresult on the stack
667 CmdBlks.push(NULL);
668 list<char> xtx;
669 TestsStack.push(xtx);
670 curb->Execute();
671 // And CommanderBloc and TestResult from the corresponding stacks
672 PopStack(false);
673 }
674 delete curb;
675 histon = ohv;
676 }
677 else CmdBlks.top()->AddLine(s, kw);
678 return(0);
679}
680else if (kw == "end") {
681 cerr << "Commander::Interpret()/syntax error - end outside for/foreach bloc \n"
682 << "line: " << s << endl;
683 return(1);
684}
685
686// Sommes-nous dans un bloc de test if then else
687if (TestsStack.top().size() > 0) { // Nous sommes ds un bloc if
688 if (kw == "else") {
689 if ((*tresit) & 2) {
690 cerr << "Commander::Interpret()/syntax error - multiple else in if bloc \n"
691 << "line: " << s << endl;
692 return(1);
693 }
694 else {
695 const char * npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
696 if ((*tresit)&1) curtestresult = false;
697 SetCurrentPrompt(npr);
698 (*tresit) |= 2;
699 return(0);
700 }
701 }
702 else if (kw == "endif") {
703 list<char>::iterator dbit = tresit;
704 tresit--;
705 TestsStack.top().erase(dbit);
706 const char * npr = "Cmd> ";
707 if (TestsStack.top().size() > 1) {
708 curtestresult = true;
709 list<char>::iterator it;
710 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
711 // Si on n'est pas ds le else et le if est faux
712 if ( !((*it)&2) && !((*it)&1) ) curtestresult = false;
713 // Si on est ds else et le if etait vrai !
714 if ( ((*it)&2) && ((*it)&1) ) curtestresult = false;
715 if (!curtestresult) break;
716 }
717
718 if (!((*tresit)&2))
719 npr = ((*tresit)&1) ? "if-T> " : "if-F> ";
720 else
721 npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
722 }
723 else curtestresult = true;
724 SetCurrentPrompt(npr);
725 return(0);
726 }
727}
728else if ((kw == "else") || (kw == "endif")) {
729 cerr << "Commander::Interpret()/syntax error - else,endif outside if bloc \n"
730 << "line: " << s << endl;
731 return(1);
732}
733
734bool fgcont = true;
735if (TestsStack.top().size() > 0) { // Resultat de if ou else
736 list<char>::iterator it;
737 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
738 // Si on n'est pas ds le else et le if est faux
739 if ( !((*it)&2) && !((*it)&1) ) fgcont = false;
740 // Si on est ds else et le if etait vrai !
741 if ( ((*it)&2) && ((*it)&1) ) fgcont = false;
742 if (!fgcont) break;
743 }
744}
745
746if ((!fgcont) && (kw != "if")) return(0);
747
748
749// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
750if (kw == "break") return(77766);
751else if (kw == "return") return(77777);
752
753// Nous ne sommes donc pas dans un bloc .... Substitution de variables
754string s2;
755int rcs ;
756
757rcs = SubstituteVars(s, s2);
758if (rcs) {
759 cerr << "Commander::Interpret()/syntax error in SubstituteVars() \n"
760 << "line: " << s << endl;
761 return(rcs);
762}
763// >>>> Separating keyword and tokens
764vector<string> tokens;
765/* decoupage en mots */
766LineToWords(s2, kw, tokens, toks, true);
767
768// Si c'est un for/foreach, on cree un nouveau bloc
769if ((kw == "foreach") || (kw == "for")) {
770 // cout << " *DBG* We got a foreach... " << endl;
771 CommanderBloc* bloc = new CommanderBloc(this, CmdBlks.top(), kw, tokens);
772 if (!bloc->CheckOK()) {
773 cerr << "Commander::Interpret() for/foreach syntax Error ! " << endl;
774 delete bloc;
775 return(1);
776 }
777 felevel++;
778 if (CmdBlks.top()) CmdBlks.top()->AddBloc(bloc);
779 else SetCurrentPrompt("for...> ");
780 CmdBlks.top() = bloc;
781 // cout << " *DBG* New Bloc created ... " << endl;
782 return(0);
783 }
784else if (kw == "if") { // Un test if
785 bool restst = true;
786 int rct = EvaluateTest(tokens, s, restst);
787 if (rct) {
788 cerr << "Commander::Interpret() if syntax Error ! " << "line: " << s << endl;
789 return(1);
790 }
791 char res_tst = (restst) ? 1 : 0;
792 TestsStack.top().push_back(res_tst);
793 if (TestsStack.top().size() == 1) tresit = TestsStack.top().begin();
794 else tresit++;
795 const char * npr = (restst) ? "if-T> " : "if-F> ";
796 SetCurrentPrompt(npr);
797}
798else if ((tokens.size() > 0) && (tokens[0] == "=")) {
799 // x = RPNExpression (Evaluation d'expression RPN)
800 tokens[0] = kw;
801 int rcev = EvalRPNExpr(tokens, s);
802 if (rcev) {
803 cerr << "Commander::Interpret() evaluation (RPN) syntax Error ! " << "line: " << s << endl;
804 return(1);
805 }
806 return(0);
807}
808else if (kw == "defscript") { // definition de script
809 if (tokens.size() > 0) {
810 if (tokens.size() < 2) tokens.push_back("");
811 curscript = new CommanderScript(this, tokens[0], tokens[1]);
812 SetCurrentPrompt("Script...> ");
813 return(0);
814 }
815 else {
816 cerr << "Commander::Interpret() No script name in defscript" << "line: " << s << endl;
817 return(1);
818 }
819}
820else {
821 // Si c'est le nom d'un script
822 sit = mScripts.find(kw);
823 if (sit != mScripts.end()) {
824 bool ohv = histon;
825 histon = false;
826 tokens.insert(tokens.begin(), kw);
827 PushStack(tokens);
828 (*sit).second->Execute(tokens);
829 PopStack(true);
830 histon = ohv;
831 }
832 // Execution de commandes
833 else rc = ExecuteCommandLine(kw, tokens, toks);
834 return(rc);
835}
836// cout << "Commander::Do() DBG KeyW= " << kw << " NbArgs= " << tokens.size() << endl;
837// for(int ii=0; ii<tokens.size(); ii++)
838// cout << "arg[ " << ii << " ] : " << tokens[ii] << endl;
839
840return(0);
841}
842
843
844/* --Methode-- */
845int Commander::LineToWords(string& line, string& kw, vector<string>& tokens,
846 string& toks, bool uq)
847{
848if (line.length() < 1) return(0);
849int nw = 1;
850size_t p = line.find_first_not_of(" ");
851line = line.substr(p);
852p = 0;
853size_t q = line.find_first_of(" ");
854size_t l = line.length();
855
856if (q < l)
857 { kw = line.substr(p,q-p); toks = line.substr(q, l-q); }
858else { kw = line.substr(p,l-p); toks = ""; }
859
860q = 0;
861while (q < l) {
862 p = toks.find_first_not_of(" \t",q+1); // au debut d'un token
863 if (p>=l) break;
864 if ( uq && ((toks[p] == '\'') || (toks[p] == '"')) ) {
865 q = toks.find(toks[p],p+1);
866 if (q>=l) {
867 cerr << "Commander::LineToWords/Syntax Error - Unbalenced quotes " << toks[p] << '.' << endl;
868 return(-1);
869 }
870 p++;
871 }
872 else {
873 q = toks.find_first_of(" \t",p); // la fin du token;
874 }
875 string token = toks.substr(p,q-p);
876 tokens.push_back(token); nw++;
877 }
878
879return(nw);
880}
881
882/* --Methode-- */
883int Commander::SubstituteVars(string & s, string & s2)
884// Variable substitution
885{
886
887int iarr = -1; // index d'element de tableau
888size_t p,q,q2,q3,l;
889
890s2="";
891p = 0;
892l = s.length();
893string vn, vv;
894while (p < l) {
895 iarr = -1;
896 q = s.find('$',p);
897 if (q > l) break;
898 q2 = s.find('\'',p);
899 if ((q2 < l) && (q2 < q)) { // On saute la chaine delimitee par ' '
900 q2 = s.find('\'',q2+1);
901 if (q2 >= l) {
902 cerr << " Syntax error - Unbalenced quotes !!! " << endl;
903 return(1);
904 }
905 s2 += s.substr(p, q2-p+1);
906 p = q2+1; continue;
907 }
908 // cout << "DBG: " << s2 << " p= " << p << " q= " << q << " L= " << l << endl;
909 if ((q>0) && (s[q-1] == '\\')) { // Escape character \$
910 s2 += (s.substr(p,q-1-p) + '$') ; p = q+1;
911 continue;
912 }
913 if (q >= l-1) {
914 cerr << " Syntax error - line ending with $ !!! " << endl;
915 return(2);
916 }
917 vn = "";
918 if ( s[q+1] == '{' ) { // Variable in the form ${name}
919 q2 = s.find('}',q+1);
920 if (q2 >= l) {
921 cerr << " Syntax error - Unbalenced brace {} !!! " << endl;
922 return(3);
923 }
924 vn = s.substr(q+2,q2-q-2);
925 q2++;
926 }
927 else if ( s[q+1] == '(' ) { // Variable in the form $(name)
928 q2 = s.find(')',q+1);
929 if (q2 >= l) {
930 cerr << " Syntax error - Unbalenced parenthesis () !!! " << endl;
931 return(3);
932 }
933 vn = s.substr(q+2,q2-q-2);
934 q2++;
935 }
936 else if ( s[q+1] == '[' ) { // Variable in the form $[varname] -> This is $$varname
937 q2 = s.find(']',q+1);
938 if (q2 >= l) {
939 cerr << " Syntax error - Unbalenced brace [] !!! " << endl;
940 return(4);
941 }
942 vn = s.substr(q+2,q2-q-2);
943 if (!GetVar(vn, vv)) return(5);
944 vn = vv;
945 q2++;
946 }
947 else {
948 q2 = s.find_first_of(" .:+-*/,[](){}&|!$\"'",q+1);
949 if (q2 > l) q2 = l;
950 q3 = q2;
951 vn = s.substr(q+1, q2-q-1);
952 // Si variable de type $varname[index] : element de tableau
953 if ((q2 < l) && (s[q2] == '[') ) {
954 q3 = s.find_first_of("]",q2+1);
955 string sia = s.substr(q2+1, q3-q2-1);
956 if (sia.length() < 1) {
957 cerr << " Syntax error - in $varname[index] : $"
958 << vn << "[" << sia <<"]" << endl;
959 return(4);
960 }
961 if (isalpha(sia[0])) {
962 string sia2;
963 if (!GetVar(sia, sia2) || (sia2.length() < 1)) {
964 cerr << " Syntax error - in $varname[index] : $"
965 << vn << "[" << sia <<"]" << endl;
966 return(4);
967 }
968 sia = sia2;
969 }
970 int rcdia = ctoi(sia.c_str(), &iarr);
971 if (rcdia < 0) {
972 cerr << " Syntax error - in $varname[iarr] : $"
973 << vn << "[" << sia <<"]" << endl;
974 return(4);
975 }
976 }
977 }
978 if (!GetVar(vn, vv)) return(5);
979 if (iarr < 0) {
980 s2 += (s.substr(p, q-p) + vv);
981 p = q2;
982 }
983 else {
984 vector<string> vs;
985 FillVStringFrString(vv, vs);
986 if (iarr >= vs.size()) {
987 cerr << " Substitution error - word index out of range in "
988 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
989 return(4);
990 }
991 else s2 += (s.substr(p, q-p) + vs[iarr]);
992 p = q3+1;
993 }
994}
995if (p < l) s2 += s.substr(p);
996
997p = s2.find_first_not_of(" \t");
998if (p < l) s2 = s2.substr(p);
999
1000return(0);
1001}
1002
1003/* --Methode-- */
1004bool Commander::GetVar(string & vn, string & vv)
1005{
1006if (vn.length() < 1) {
1007 cerr << " Commander::SubstituteVar/Error: length(varname=" << vn << ")<1 !" << endl;
1008 vv = ""; return(false);
1009}
1010// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1011int ka = 0;
1012if (vn == "#") {
1013 if (ArgsStack.empty()) {
1014 cerr << " Commander::SubstituteVar/Error: ArgsStack empty ! "
1015 << " ($" << vn << ")" << endl;
1016 vv = ""; return(false);
1017 }
1018 char buff[32];
1019 long an = ArgsStack.top().size();
1020 sprintf(buff,"%ld", an);
1021 vv = buff; return(true);
1022}
1023else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1024 if (ArgsStack.empty()) {
1025 cerr << " Commander::SubstituteVar/Error: ArgsStack empty ! "
1026 << " ($" << vn << ")" << endl;
1027 vv = ""; return(false);
1028 }
1029 if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) {
1030 cerr << " Commander::SubstituteVar/Error: Undefined variable ! "
1031 << " ($" << vn << ")" << endl;
1032 vv = ""; return(false);
1033 }
1034 vv = ArgsStack.top()[ka]; return(true);
1035}
1036else if (vn[0] == '#') { // Variable de type $#vname --> size(vname)
1037 vn = vn.substr(1);
1038 if (!HasVariable(vn) ) {
1039 cerr << " Commander::SubstituteVarError: Undefined variable "
1040 << vn << " ! " << endl;
1041 vv = ""; return(false);
1042 }
1043 vn = GetVariable(vn);
1044 vector<string> vs;
1045 FillVStringFrString(vn, vs);
1046 char buff[32];
1047 sprintf(buff,"%d", (int)vs.size());
1048 vv = buff; return(true);
1049 }
1050else { // variable ordinaire geree par NamedObjMgr
1051 if ( (!HasVariable(vn)) ) {
1052 cerr << " Commander::SubstituteVarError: Undefined variable "
1053 << vn << " ! " << endl;
1054 vv = ""; return(false);
1055 }
1056 vv = GetVariable(vn); return(true);
1057}
1058
1059return(false);
1060}
1061/* --Methode-- */
1062string Commander::GetVariable(string const & key)
1063{
1064 if ((key.length() < 1) || (! isalpha(key[0])) ) {
1065 cout << "Commander::GetVariable( " << key << ") Bad VarName " << endl;
1066 return("");
1067 }
1068 // cout << " DEBUG::GetVar " << variables << endl;
1069 return(variables.GetS(key));
1070}
1071
1072/* --Methode-- */
1073bool Commander::HasVariable(string const & key)
1074{
1075 if ((key.length() < 1) || (! isalpha(key[0])) ) {
1076 cout << "Commander::HasVar( " << key << ") Bad VarName " << endl;
1077 return(false);
1078 }
1079 return(variables.HasKey(key));
1080}
1081
1082/* --Methode-- */
1083bool Commander::SetVar(string const & key, string const & val)
1084{
1085 if ((key.length() < 1) || (! isalpha(key[0])) ) {
1086 cout << "Commander::SetVar( " << key << " ...) Bad VarName " << endl;
1087 return(false);
1088 }
1089 bool fg = variables.HasKey(key);
1090 variables.SetS(key, val);
1091 // cout << " DEBUG::SetVar " << variables << endl;
1092 return fg;
1093}
1094
1095/* --Methode-- */
1096bool Commander::DeleteVar(string const & key)
1097{
1098 if ((key.length() < 1) || (! isalpha(key[0])) ) {
1099 cout << "Commander::DeleteVar( " << key << ") Bad VarName " << endl;
1100 return(false);
1101 }
1102 return(variables.DeleteKey(key));
1103}
1104
1105/* --Methode-- */
1106void Commander::ListVars()
1107{
1108 cout << " ---- Commander::ListVars() List of defined variables ---- "
1109 << endl;
1110 cout << variables;
1111 cout << "---------------------------------------------------------- "
1112 << endl;
1113}
1114
1115/* --Methode-- */
1116string Commander::GetTmpDir()
1117{
1118 return("/tmp");
1119}
1120
1121/* --Methode-- */
1122void Commander::SetCurrentPrompt(const char* pr)
1123{
1124 curprompt = pr;
1125}
1126
1127/* --Methode-- */
1128void Commander::ShowMessage(const char * msg, int att)
1129{
1130 cout << msg ;
1131}
1132
1133
1134
1135/* --Methode-- */
1136int Commander::EvaluateTest(vector<string> & args, string & line, bool & res)
1137{
1138 res = true;
1139 if ((args.size() != 6) || (args[5] != "then") ||
1140 (args[0] != "(") || (args[4] != ")") ) return(1);
1141 if (args[2] == "==") res = (args[1] == args[3]);
1142 else if (args[2] == "!=") res = (args[1] != args[3]);
1143 else if (args[2] == "<")
1144 res = (atof(args[1].c_str()) < atof(args[3].c_str()));
1145 else if (args[2] == ">")
1146 res = (atof(args[1].c_str()) > atof(args[3].c_str()));
1147 else if (args[2] == "<=")
1148 res = (atof(args[1].c_str()) <= atof(args[3].c_str()));
1149 else if (args[2] == ">=")
1150 res = (atof(args[1].c_str()) >= atof(args[3].c_str()));
1151 else return(2);
1152 return(0);
1153}
1154
1155/* Operations sur le stack RPN */
1156inline bool Check_myRPNStack_(stack<double>& s, double& x, string& line)
1157{
1158 if (s.empty()) {
1159 cerr << "Commander::EvalRPNExpr: syntax error / empty RPN stack " << line << endl;
1160 return true;
1161 }
1162 else x = s.top();
1163 return false;
1164}
1165inline bool Check_myRPNStack_(stack<double>& s, double& x, double& y, string& line)
1166{
1167 if (s.size() < 2) {
1168 cerr << "Commander::EvalRPNExpr: syntax error / RPN stack size < 2 " << line << endl;
1169 return true;
1170 }
1171 else {
1172 x = s.top(); s.pop(); y = s.top();
1173 }
1174 return false;
1175}
1176
1177inline void Print_myRPNStack_(stack<double> s)
1178{
1179 if (s.empty())
1180 cout << "Commander::EvalRPNExpr/PrintStack: Empty stack " << endl;
1181 else {
1182 int k = 0;
1183 cout << "Commander::EvalRPNExpr/PrintStack: Size()= " << s.size() << endl;
1184 while( !s.empty() ) {
1185 cout << " " << k << ": " << s.top() << " ";
1186 if (k == 0) cout << " (x) " << endl;
1187 else if (k == 1) cout << " (y) " << endl;
1188 else if (k == 2) cout << " (z) " << endl;
1189 else cout << endl;
1190 s.pop(); k++;
1191 }
1192 }
1193
1194}
1195
1196int Sum_RPNStack_(stack<double>& s, double& sx, double& sx2, string& line)
1197{
1198 sx = sx2 = 0.;
1199 int nn = 0;
1200 double x = 0.;
1201 while( !s.empty() ) {
1202 x = s.top(); s.pop();
1203 sx += x; sx2 += x*x;
1204 nn++;
1205 }
1206 return(nn);
1207}
1208
1209int Product_RPNStack_(stack<double>& s, double& px, string& line)
1210{
1211 px = 1.;
1212 int nn = 0;
1213 double x = 0.;
1214 while( !s.empty() ) {
1215 x = s.top(); s.pop();
1216 px *= x; nn++;
1217 }
1218 return(nn);
1219}
1220
1221/* --Methode-- */
1222int Commander::EvalRPNExpr(vector<string> & args, string & line)
1223{
1224
1225 if (args.size() < 2) {
1226 cerr << "Commander::EvalRPNExpr: syntax error / missing arguments " << line << endl;
1227 return(1);
1228 }
1229 else if (args.size() == 2) {
1230 SetVar(args[0], args[1]);
1231 return(0);
1232 }
1233
1234 double x,y;
1235 x = y = 0.;
1236 stack<double> rpnstack; // Stack des operations en RPN
1237 for(int k=1; k<args.size(); k++) {
1238 // Les 4 operations de base + - * /
1239 if (args[k] == "+") {
1240 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1241 rpnstack.top() = y+x;
1242 }
1243 else if (args[k] == "-") {
1244 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1245 rpnstack.top() = y-x;
1246 }
1247 else if (args[k] == "*") {
1248 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1249 rpnstack.top() = y*x;
1250 }
1251 else if (args[k] == "/") {
1252 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1253 rpnstack.top() = y/x;
1254 }
1255 else if (args[k] == "%") {
1256 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1257 rpnstack.top() = (int)y % (int)x;
1258 }
1259 // Les constantes : e , pi
1260 else if (args[k] == "e") {
1261 rpnstack.push(M_E);
1262 }
1263 else if (args[k] == "pi") {
1264 rpnstack.push(M_PI);
1265 }
1266 // Les fonctions usuelles a 1 argument f(x)
1267 else if (args[k] == "cos") {
1268 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1269 rpnstack.top() = cos(x);
1270 }
1271 else if (args[k] == "sin") {
1272 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1273 rpnstack.top() = sin(x);
1274 }
1275 else if (args[k] == "tan") {
1276 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1277 rpnstack.top() = tan(x);
1278 }
1279 else if (args[k] == "acos") {
1280 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1281 rpnstack.top() = acos(x);
1282 }
1283 else if (args[k] == "asin") {
1284 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1285 rpnstack.top() = asin(x);
1286 }
1287 else if (args[k] == "atan") {
1288 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1289 rpnstack.top() = atan(x);
1290 }
1291 else if (args[k] == "chs") {
1292 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1293 rpnstack.top() = -x;
1294 }
1295 else if (args[k] == "sqrt") {
1296 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1297 rpnstack.top() = sqrt(x);
1298 }
1299 else if (args[k] == "sq") { // x^2
1300 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1301 rpnstack.top() = x*x;
1302 }
1303 else if (args[k] == "log") {
1304 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1305 rpnstack.top() = log(x);
1306 }
1307 else if (args[k] == "log10") {
1308 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1309 rpnstack.top() = log10(x);
1310 }
1311 else if (args[k] == "exp") {
1312 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1313 rpnstack.top() = exp(x);
1314 }
1315 else if (args[k] == "fabs") {
1316 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1317 rpnstack.top() = fabs(x);
1318 }
1319 else if (args[k] == "floor") {
1320 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1321 rpnstack.top() = floor(x);
1322 }
1323 else if (args[k] == "ceil") {
1324 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1325 rpnstack.top() = ceil(x);
1326 }
1327 // trunc et nint vire - ca ne compile pas sous linux - Reza 01/2003
1328 else if (args[k] == "deg2rad") {
1329 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1330 rpnstack.top() = x*M_PI/180.;
1331 }
1332 else if (args[k] == "rad2deg") {
1333 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1334 rpnstack.top() = x*180./M_PI;
1335 }
1336 // Les fonctions usuelles a 2 argument f(x,y)
1337 else if (args[k] == "pow") {
1338 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1339 rpnstack.top() = pow(y,x);
1340 }
1341 else if (args[k] == "atan2") {
1342 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1343 rpnstack.top() = atan2(x,y);
1344 }
1345 // generateur aleatoire
1346 else if (args[k] == "rand") {
1347 double rnd = drand01();
1348 rpnstack.push(rnd);
1349 }
1350 else if (args[k] == "norand") {
1351 double rnd = GauRnd(0., 1.);
1352 rpnstack.push(rnd);
1353 }
1354 // Fonction a N arguments - Somme, produit, etc ...
1355 else if ((args[k] == "sum") || (args[k] == "mean") || (args[k] == "sigmean") ||
1356 (args[k] == "sigma") || (args[k] == "sigma2") ) {
1357 double sx, sx2;
1358 int nn = Sum_RPNStack_(rpnstack, sx, sx2, line);
1359 if (args[k] == "sum") rpnstack.push(sx);
1360 else {
1361 if (nn == 0) {
1362 cerr << "Commander::EvalRPNExpr: mean/sigma error- RPN stack empty: "
1363 << line << endl;
1364 return(1);
1365 }
1366 double fnn = nn;
1367 if ((args[k] == "sigma") || (args[k] == "sigmean"))
1368 rpnstack.push(sqrt(sx2/fnn-(x*x/(fnn*fnn))));
1369 else if ((args[k] == "mean") || (args[k] == "sigmean")) rpnstack.push(sx/fnn);
1370 else rpnstack.push(sx2/fnn-(x*x/(fnn*fnn)));
1371 }
1372 }
1373 else if (args[k] == "product") {
1374 double px;
1375 int nn = Product_RPNStack_(rpnstack, px, line);
1376 if (nn == 0) {
1377 cerr << "Commander::EvalRPNExpr: product error- RPN stack empty: "
1378 << line << endl;
1379 return(1);
1380 }
1381 rpnstack.push(px);
1382 }
1383 // Fonctions de manipulation de stack
1384 else if (args[k] == "print") {
1385 Print_myRPNStack_(rpnstack);
1386 }
1387 else if (args[k] == "x<>y") {
1388 if ( Check_myRPNStack_(rpnstack, x, y, line) ) return(1);
1389 rpnstack.top() = x; rpnstack.push(y);
1390 }
1391 else if (args[k] == "pop") {
1392 rpnstack.pop();
1393 }
1394 else if (args[k] == "push") {
1395 if (rpnstack.empty()) rpnstack.push(0.);
1396 else rpnstack.push(rpnstack.top());
1397 }
1398 // On met un nombre sur le stack
1399 else {
1400 char * esptr;
1401 x = strtod(args[k].c_str(), &esptr);
1402 // if (ctof(args[k].c_str(),&x) < 0) {
1403 if (esptr == args[k].c_str()) {
1404 cerr << "Commander::EvalRPNExpr: syntax error near " << args[k]
1405 << " in expression: \n" << line << endl;
1406 return(2);
1407 }
1408 rpnstack.push(x);
1409 }
1410
1411 }
1412
1413 if ( Check_myRPNStack_(rpnstack, x, line) ) return(1);
1414 char buff[64];
1415 sprintf(buff, "%g", x);
1416 string res = buff;
1417 SetVar(args[0], res);
1418 return(0);
1419}
1420
1421/* --Methode-- */
1422void Commander::PushStack(vector<string>& args)
1423{
1424 // We push the argument list (args) on the stack
1425 ArgsStack.push(args);
1426 // We push also CommanderBloc and testresult on the stack
1427 CmdBlks.push(NULL);
1428 list<char> xtx;
1429 TestsStack.push(xtx);
1430
1431}
1432
1433/* --Methode-- */
1434void Commander::PopStack(bool psta)
1435{
1436 // We remove the argument list (args) from the stack
1437 if (psta) ArgsStack.pop();
1438 // And CommanderBloc and TestResult from the corresponding stacks
1439 CommanderBloc* curb = CmdBlks.top();
1440 while (curb != NULL) {
1441 CommanderBloc* parb = curb->Parent();
1442 delete curb; curb = parb;
1443 }
1444 CmdBlks.pop();
1445 TestsStack.pop();
1446}
1447
1448/* --Methode-- */
1449int Commander::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
1450{
1451int rc = 0;
1452
1453// >>>>>>>>>>> Commande d'interpreteur
1454if (kw == "help") {
1455 if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl;
1456 else {
1457 string kwh = "Commander";
1458 cout << GetUsage(kwh) << endl;
1459 }
1460 }
1461
1462else if (kw == "set") {
1463 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: set varname string" << endl; return(0); }
1464 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1465 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1466 return(0);
1467 }
1468 // string xx = tokens[1];
1469 // for (int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk] );
1470 SetVar(tokens[0], tokens[1]);
1471 }
1472
1473else if (kw == "getvar") {
1474 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: getvar newvarname varname" << endl; return(0); }
1475 if (!HasVariable(tokens[1])) {
1476 cerr << "Error - No " << tokens[1] << " Variable " << endl;
1477 return(0);
1478 }
1479 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1480 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1481 return(0);
1482 }
1483 SetVar(tokens[0], GetVariable(tokens[1]) );
1484 }
1485
1486else if (kw == "alias") {
1487 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: alias aliasname string" << endl; return(0); }
1488 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1489 cerr << "Commander::Interpret()/Error alias name should start with alphabetic" << endl;
1490 return(0);
1491 }
1492 string xx = tokens[1];
1493 for (int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
1494 mAliases[tokens[0]] = xx;
1495 }
1496
1497else if (kw == "unset") {
1498 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: unset varname" << endl; return(0); }
1499 if (HasVariable(tokens[0])) DeleteVar(tokens[0]) ;
1500 else cerr << "Commander::Interpret() No variable with name " << tokens[0] << endl;
1501 }
1502 else if (kw == "rpneval") { // Evaluation d'expression en notation polonaise inverse
1503 return(EvalRPNExpr(tokens, toks));
1504}
1505else if (kw == "echo") {
1506 for (int ii=0; ii<tokens.size(); ii++)
1507 cout << tokens[ii] << " " ;
1508 cout << endl;
1509 }
1510else if (kw == "echo2file") {
1511 if (tokens.size() < 1) {
1512 cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;
1513 return(0);
1514 }
1515 ofstream ofs(tokens[0].c_str(), ios::app);
1516 for (int ii=1; ii<tokens.size(); ii++)
1517 ofs << tokens[ii] << " " ;
1518 ofs << endl;
1519 }
1520else if (kw == "readstdin") {
1521 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: readstdin varname" << endl; return(0); }
1522 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1523 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1524 return(0);
1525 }
1526 ShowMessage(">>> Reading From StdIn \n", _MAGENTA_);
1527 cout << tokens[0] << " ? " << endl;
1528 SetVar(tokens[0], GetStringFrStdin(this) );
1529 }
1530
1531else if (kw == "listvars") ListVars();
1532else if (kw == "listalias") {
1533 cout << "Commander::Interpret() Alias List , AliasName = Value \n";
1534 CmdStrList::iterator it;
1535 for(it = mAliases.begin(); it != mAliases.end(); it++)
1536 cout << (*it).first << " = " << (*it).second << "\n";
1537 cout << endl;
1538 }
1539else if (kw == "listcommands") {
1540 cout << "---- Commander::Interpret() Command List ----- \n";
1541 CmdExmap::iterator it;
1542 int kc = 0;
1543 for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
1544 cout << (*it).first << " ";
1545 kc++;
1546 if (kc >= 5) { cout << "\n"; kc = 0; }
1547 }
1548 cout << endl;
1549 }
1550else if (kw == "listscripts") {
1551 cout << "---- Commander::Interpret() Script List ----- \n";
1552 for(ScriptList::iterator sit = mScripts.begin();
1553 sit != mScripts.end(); sit++)
1554 cout << " Script: " << (*sit).second->Name() << " - "
1555 << (*sit).second->Comment() << endl;
1556}
1557else if (kw == "clearscript") {
1558 if (tokens.size() < 1) {
1559 cout << "Commander::Interpret() Usage: clearscript scriptname" << endl;
1560 return(0);
1561 }
1562 ScriptList::iterator sit = mScripts.find(tokens[0]);
1563 if (sit == mScripts.end()) {
1564 cout << "Commander::Interpret() No script with name" << tokens[0] << endl;
1565 return(0);
1566 }
1567 else {
1568 delete (*sit).second;
1569 mScripts.erase(sit);
1570 cout << "Commander::Interpret() script " << tokens[0] << " cleared" << endl;
1571 return(0);
1572 }
1573}
1574else if (kw == "traceon") { cout << "Commander::Interpret() -> Trace ON mode " << endl; trace = true; }
1575else if (kw == "traceoff") { cout << "Commander::Interpret() -> Trace OFF mode " << endl; trace = false; }
1576else if (kw == "timingon") {
1577 cout << "Commander::Interpret() -> Timing ON mode " << endl;
1578 if (gltimer) delete gltimer; gltimer = new Timer("PIA-CmdInterpreter "); timing = true;
1579 }
1580else if (kw == "timingoff") {
1581 cout << "Commander::Interpret() -> Timing OFF mode " << endl;
1582 if (gltimer) delete gltimer; gltimer = NULL; timing = false;
1583 }
1584else if (kw == "exec") {
1585 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: exec filename" << endl; return(0); }
1586 ExecFile(tokens[0], tokens);
1587 }
1588else if (kw == "autoiniranf") {
1589 Auto_Ini_Ranf(1);
1590 return(0);
1591}
1592else if (kw == "shell") {
1593 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: shell cmdline" << endl; return(0); }
1594 string cmd;
1595 for (int ii=0; ii<tokens.size(); ii++)
1596 cmd += (tokens[ii] + ' ');
1597 system(cmd.c_str());
1598 }
1599else if (kw == "cshell") {
1600 if(tokens.size()<1) {cout<<"Commander::Interpret() Usage: cshell cmdline"<<endl; return(0);}
1601 string cmd="";
1602 for(int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
1603 CShellExecute(cmd);
1604 }
1605
1606// Execution d'une commande enregistree
1607else rc = ExecuteCommand(kw, tokens, toks);
1608
1609if (timing) gltimer->Split();
1610return(rc);
1611}
1612
1613/* --Methode-- */
1614int Commander::ParseLineExecute(string& line, bool qw)
1615 // Si qw == true, on decoupe entre '' ou "" ou espaces
1616{
1617vector<string> tokens;
1618string kw, toks;
1619if (line.length() < 1) return(0);
1620LineToWords(line, kw, tokens, toks, qw);
1621return(ExecuteCommand(kw, tokens, toks));
1622}
1623
1624/* --Methode-- */
1625int Commander::ExecuteCommand(string& keyw, vector<string>& args, string& toks)
1626{
1627 int rc = -1;
1628 CmdExmap::iterator it = cmdexmap.find(keyw);
1629 if (it == cmdexmap.end()) cout << "No such command : " << keyw << " ! " << endl;
1630 else {
1631 if ((*it).second.cex) rc = (*it).second.cex->Execute(keyw, args, toks);
1632 else cout << "Dont know how to execute " << keyw << " ? " << endl;
1633 }
1634 return(rc);
1635}
1636
1637/* --Methode-- */
1638int Commander::ExecFile(string& file, vector<string>& args)
1639{
1640char line_buff[512];
1641FILE *fip;
1642
1643if ( (fip = fopen(file.c_str(),"r")) == NULL ) {
1644 if (file.find('.') >= file.length()) {
1645 cout << "Commander::Exec(): Error opening file " << file << endl;
1646 file += ".pic";
1647 cout << " Trying file " << file << endl;
1648 fip = fopen(file.c_str(),"r");
1649 }
1650 }
1651
1652if(fip == NULL) {
1653 cerr << "Commander::Exec() Error opening file " << file << endl;
1654 hist << "##! Commander::Exec() Error opening file " << file << endl;
1655 return(0);
1656 }
1657
1658// hist << "### Executing commands from " << file << endl;
1659
1660PushStack(args);
1661if (trace) {
1662 ShowMessage("### Executing commands from ", _MAGENTA_);
1663 ShowMessage(file.c_str(), _MAGENTA_);
1664 ShowMessage("\n", _MAGENTA_);
1665 }
1666
1667bool ohv = histon;
1668histon = false;
1669while (fgets(line_buff,511,fip) != NULL)
1670 {
1671 if (trace) ShowMessage(line_buff, _MAGENTA_);
1672 line_buff[strlen(line_buff)-1] = '\0'; /* LF/CR de la fin */
1673 string line(line_buff);
1674 if (Interpret(line) == 77777) break;
1675 }
1676histon = ohv;
1677
1678// hist << "### End of Exec( " << file << " ) " << endl;
1679if (trace) {
1680 ShowMessage("### End of Exec( ", _MAGENTA_);
1681 ShowMessage(file.c_str(), _MAGENTA_);
1682 ShowMessage(" ) \n", _MAGENTA_);
1683 }
1684
1685PopStack(true);
1686
1687return(0);
1688}
1689
1690/* --Methode-- */
1691int Commander::CShellExecute(string cmd)
1692{
1693 if(cmd.size()<=0) return -1;
1694
1695 string fname = GetTmpDir(); fname += "cshell_exec_pia.csh";
1696
1697 string cmdrm = "rm -f " + fname;
1698 system(cmdrm.c_str());
1699
1700 FILE *fip = fopen(fname.c_str(),"w");
1701 if(fip==NULL) {
1702 cout << "Commander/CShellExecute_Error: fopen("<<fname<<") failed"<<endl;
1703 return -2;
1704 }
1705 fprintf(fip,"#!/bin/csh\n\n");
1706 fprintf(fip,"%s\n",cmd.c_str());
1707 fprintf(fip,"\nexit 0\n");
1708 fclose(fip);
1709
1710 cmd = "csh "; cmd += fname;
1711 system(cmd.c_str());
1712
1713 system(cmdrm.c_str());
1714
1715 return 0;
1716}
1717
1718static string* videstr = NULL;
1719/* --Methode-- */
1720string& Commander::GetUsage(const string& kw)
1721{
1722bool fndok = false;
1723CmdExmap::iterator it = cmdexmap.find(kw);
1724if (it == cmdexmap.end()) {
1725 it = helpexmap.find(kw);
1726 if (it != helpexmap.end()) fndok = true;
1727 }
1728 else fndok = true;
1729if (fndok) return( (*it).second.us );
1730// Keyword pas trouve
1731if (videstr == NULL) videstr = new string("");
1732*videstr = "Nothing known about " + kw + " ?? ";
1733return(*videstr);
1734
1735}
1736
1737
1738/* Les definitions suivantes doivent se trouver ds l'en-tete du fichier LaTeX
1739 \newcommand{\piacommand}[1]{
1740 \framebox{\bf \Large #1 } \index{#1} % (Command)
1741 }
1742
1743 \newcommand{\piahelpitem}[1]{
1744 \framebox{\bf \Large #1 } \index{#1} (Help item)
1745 }
1746
1747 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
1748*/
1749
1750// Fonction qui remplace tout caractere non alphanumerique en Z
1751static void check_latex_reflabel(string & prl)
1752{
1753 for(int k=0; k<prl.length(); k++)
1754 if (! isalnum(prl[k]) ) prl[k] = 'Z';
1755}
1756
1757// Fonction qui remplace _ en \_
1758static string check_latex_underscore(string const & mot)
1759{
1760 string rs;
1761 for(int k=0; k<mot.length(); k++) {
1762 if (mot[k] == '_') rs += "\\_";
1763 else rs += mot[k];
1764 }
1765 return rs;
1766}
1767
1768/* --Methode-- */
1769void Commander::HelptoLaTeX(string const & fname)
1770{
1771FILE *fip;
1772if ((fip = fopen(fname.c_str(), "w")) == NULL) {
1773 cout << "Commander::HelptoLaTex_Error: fopen( " << fname << endl;
1774 return;
1775 }
1776
1777fputs("% ----- Liste des groupes de Help ----- \n",fip);
1778fputs("List of {\\bf piapp} on-line Help groups: \n", fip);
1779fputs("\\begin{itemize} \n",fip);
1780string prl;
1781string mol;
1782CmdHGroup::iterator it;
1783for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
1784 if ((*it).first == "All") continue;
1785 prl = (*it).first; check_latex_reflabel(prl);
1786 mol = check_latex_underscore((*it).first);
1787 fprintf(fip,"\\item {\\bf %s } (p. \\pageref{%s}) \n",
1788 mol.c_str(), prl.c_str());
1789}
1790
1791fputs("\\end{itemize} \n",fip);
1792
1793fputs("\\vspace*{10mm} \n",fip);
1794
1795CmdExmap::iterator ite;
1796fputs("% ----- Liste de toutes les commandes et help item ----- \n",fip);
1797fputs("\\vspace{5mm} \n",fip);
1798// fputs("\\begin{table}[h!] \n", fip);
1799fputs("\\begin{center} \n ", fip);
1800fputs("\\rule{2cm}{1mm} List of {\\bf piapp} Help items \\rule{2cm}{1mm} \\\\ \n", fip);
1801fputs("\\vspace{3mm} \n",fip);
1802fputs("\\begin{tabular}{llllll} \n", fip);
1803int kt = 0;
1804for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
1805 prl = (*ite).first; check_latex_reflabel(prl);
1806 mol = check_latex_underscore((*ite).first);
1807 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
1808 kt++;
1809 if (kt < 3) fputs(" & ", fip);
1810 else { fputs(" \\\\ \n", fip); kt = 0; }
1811 }
1812if (kt == 1) fputs(" & & & \\\\ \n", fip);
1813else if (kt == 2) fputs(" & \\\\ \n", fip);
1814fputs("\\end{tabular} \n", fip);
1815fputs("\\end{center} \n", fip);
1816//fputs("\\end{table} \n", fip);
1817fputs("\\newpage \n",fip);
1818
1819int gid;
1820for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
1821 gid = (*it).second.gid;
1822 if (gid == 0) continue;
1823 // fputs("\\begin{table}[h!] \n",fip);
1824 fputs("\\vspace{6mm} \n",fip);
1825 fputs("\\begin{center} \n ", fip);
1826 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
1827 (*it).first.c_str());
1828 fputs("\\vspace{3mm} \n",fip);
1829 fputs("\\begin{tabular}{llllll} \n", fip);
1830 kt = 0;
1831 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
1832 if ((*ite).second.group != gid) continue;
1833 prl = (*ite).first; check_latex_reflabel(prl);
1834 mol = check_latex_underscore((*ite).first);
1835 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
1836 kt++;
1837 if (kt < 3) fputs(" & ", fip);
1838 else { fputs(" \\\\ \n", fip); kt = 0; }
1839 }
1840 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
1841 if ((*ite).second.group != gid) continue;
1842 prl = (*ite).first; check_latex_reflabel(prl);
1843 mol = check_latex_underscore((*ite).first);
1844 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
1845 kt++;
1846 if (kt < 3) fputs(" & ", fip);
1847 else { fputs(" \\\\ \n", fip); kt = 0; }
1848 }
1849 if (kt == 1) fputs(" & & & \\\\ \n", fip);
1850 else if (kt == 2) fputs(" & \\\\ \n", fip);
1851 fputs("\\end{tabular} \n", fip);
1852 fputs("\\end{center} \n", fip);
1853 // fputs("\\end{table} \n",fip);
1854 // fputs("\\vspace{5mm} \n",fip);
1855}
1856// fputs("\\newline \n",fip);
1857
1858fputs("% ----- Liste des commandes dans chaque groupe ----- \n",fip);
1859fputs("\\newpage \n",fip);
1860
1861for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
1862 gid = (*it).second.gid;
1863 if (gid == 0) continue;
1864 prl = (*it).first; check_latex_reflabel(prl);
1865 fprintf(fip,"\\subsection{%s} \\label{%s} \n",
1866 (*it).first.c_str(), prl.c_str());
1867 if ((*it).second.desc.length() > 0)
1868 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
1869 fprintf(fip,"\\noindent \n");
1870 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
1871 if ((*ite).second.group != gid) continue;
1872 prl = (*ite).first; check_latex_reflabel(prl);
1873 mol = check_latex_underscore((*ite).first);
1874 fprintf(fip,"\\piahelpitem{%s} \\label{%s} \n",
1875 mol.c_str(), prl.c_str());
1876 fputs("\\begin{verbatim} \n",fip);
1877 fprintf(fip,"%s\n", (*ite).second.us.c_str());
1878 fputs("\\end{verbatim} \n",fip);
1879 }
1880 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
1881 if ((*ite).second.group != gid) continue;
1882 prl = (*ite).first; check_latex_reflabel(prl);
1883 mol = check_latex_underscore((*ite).first);
1884 fprintf(fip,"\\piacommand{%s} \\label{%s} \n",
1885 mol.c_str(), prl.c_str());
1886 fputs("\\begin{verbatim} \n",fip);
1887 fprintf(fip,"%s\n", (*ite).second.us.c_str());
1888 fputs("\\end{verbatim} \n",fip);
1889 }
1890}
1891
1892fclose(fip);
1893cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
1894
1895return;
1896}
1897
1898
1899
Note: See TracBrowser for help on using the repository browser.