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

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

Amelioration classe SOPHYA::Commander, en particulier Ajout description d'un HelpGroup - Reza 27 Nov 2003

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