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

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

Introduction de la classe Commander, qui devra devenir la classe de base pour PIACmd (piapp) - Reza 06/10/2003

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