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

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

Correction bugs ds CExpression/RPNExpression et adaptation classe Commander avec utilisation classe CExpressionEvaluator - Reza 16 Mars 2004

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