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

Last change on this file since 4055 was 4034, checked in by ansari, 14 years ago

1/ Corrections dans commander.cc des bugs de forinfile et boucles imbriquees
2/ Différentiation instruction break et breakall - gestion correcte des if
lors de la sortie de boucle. Reza 14/11/2011

File size: 68.0 KB
RevLine 
[2615]1#include "sopnamsp.h"
[2446]2#include "commander.h"
3#include <stdio.h>
4#include <stdlib.h>
[3619]5#include <string.h>
[2518]6#include <unistd.h>
[2446]7#include <ctype.h>
8#include <math.h>
[2943]9#include <signal.h>
[2446]10
11#include "strutil.h"
12#include "strutilxx.h"
[2512]13#include "cexpre.h"
14#include "rpneval.h"
[2446]15#include "srandgen.h"
[2671]16#include "zthread.h"
[2446]17
18
[2483]19namespace SOPHYA {
[2518]20
[3577]21//--------------------------------------------------
22// Pour ecrire une valeur double sous forme de string
23// sans perte de precision, et si possible de maniere
[3581]24// lisible (%g, sinon format adapte jusqu'a %.17e)
25static char cval_strbuff_[80];
26////1er essai binaire: char * cval_dble2str(double v)
27////1er essai binaire: {
28////1er essai binaire: char* str1 = cval_strbuff_;
29////1er essai binaire: sprintf(str1,"%g",v);
30////1er essai binaire: char* str2 = cval_strbuff_+32;
31////1er essai binaire: sprintf(str2,"%.17e",v);
32////1er essai binaire: double x1 = atof(str1);
33////1er essai binaire: double x2 = atof(str2);
34////1er essai binaire: double fx = fabs(v);
35////1er essai binaire: if (fx>0. && fabs(x2-x1)/fx>1e-12) return str2;
36////1er essai binaire: else return str1;
37////1er essai binaire: }
[3577]38char * cval_dble2str(double v)
39{
[3581]40 char* strgood = cval_strbuff_; sprintf(strgood,"%g",v);
41 char* strfull = cval_strbuff_+32; sprintf(strfull,"%.17e",v);
42 char* strform = cval_strbuff_+64;
43 double x1 = atof(strfull), fx = fabs(x1);
44 if(fx>0.) {
45 for(int i=7;i<=17;i+=2) { // increment de 2 pour aller + vite
46 double x2 = atof(strgood);
47 if(fabs(x2-x1)/fx<1.e-16) break;
48 sprintf(strform,"%%.%de",i);
49 sprintf(strgood,strform,v);
50 }
51 }
52 return strgood;
[3577]53}
54//--------------------------------------------------
55
[2518]56// Differents code de retour specifiques
[4034]57#define CMD_RETURN_RC 99900
58#define CMD_BREAK_RC 99990
59#define CMD_LOOPBREAK_RC 99910
60#define CMD_BREAKALL_RC 99998
61#define CMD_BREAKEXE_RC 99999
[2518]62
[2446]63// ------------------------------------------------------------
64// Bloc de commandes (Foreach, ...)
65// Classe CommanderBloc
66// ------------------------------------------------------------
67/*!
[2598]68 \internal
[2446]69 \class SOPHYA::CommanderBloc
70 \ingroup SysTools
[2598]71 Class for internal use by class Commander to handle loops
[2446]72*/
73class CommanderBloc {
74public:
[2483]75 enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat,
76 BT_ForeachLineInFile };
[2446]77
78 CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args);
79 ~CommanderBloc();
80 inline CommanderBloc* Parent() { return(parent); }
81 inline bool CheckOK() { return blkok; }
82 inline void AddLine(string& line)
83 { lines.push_back(line); bloclineid.push_back(lines.size()); }
84 void AddLine(string& line, string& kw);
85 inline void AddBloc(CommanderBloc* blk)
86 { blocs.push_back(blk); bloclineid.push_back(-blocs.size()); }
[2518]87
88 // Execution complete du bloc (boucle)
89 int Execute();
90 // Execution pour un element de bloc
91 int ExecuteOnce(string& lvv);
92
[2446]93 inline int& TestLevel() { return testlevel; }
94 inline int& LoopLevel() { return looplevel; }
95 inline bool CheckBloc()
96 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)); }
97
98protected:
99 Commander* _commander;
100 CommanderBloc* parent;
101 bool blkok; // true -> block OK
102 BType typ; // foreach , integer loop, float loop, test
103 string varname;
[2483]104 string filename; // forinfile bloc
[2446]105 vector<string> strlist;
106 vector<string> lines;
107 vector<CommanderBloc *> blocs;
108 vector<int> bloclineid;
109 int i1,i2,di;
110 float f1,f2,df;
111 int testlevel; // niveau d'imbrication des if
112 int looplevel; // niveau d'imbrication des for/foreach
113 bool scrdef; // true -> commande defscript ds for/foreach
114};
115
116/* --Methode-- */
117CommanderBloc::CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args)
118{
119_commander = piac;
120parent = par;
121blkok = false;
122typ = BT_None;
123i1 = 0; i2 = -1; di = 1;
124f1 = 0.; f2 = -1.; df = 1.;
125testlevel = looplevel = 0;
126scrdef = false;
127
128if ((args.size() < 2) || !isalpha((int)args[0][0]) ) return;
[2483]129if ((kw != "foreach") && (kw != "for") && (kw != "forinfile")) return;
[2518]130if (!piac->CheckVarName(args[0])) return;
131varname = args[0];
132
[2446]133//if (isalpha((int)args[1][0]) ) { This is a foreach bloc with string list
[2483]134if (kw == "forinfile") {
135 filename = args[1];
[2518]136 typ = BT_ForeachLineInFile;
[2483]137 blkok = true;
138}
139else if (kw == "foreach" ) { // This is a foreach bloc with string list
[2518]140 if ( (args[1] == "(") && (args[args.size()-1] == ")") ) {
141 // foreach varname ( w1 w2 w3 ... )
[3581]142 for(unsigned int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
[2518]143 }
144 else {
145 // foreach varname WordVectorName
146 if (!piac->GetVar(args[1], strlist)) return;
147 }
148 if (strlist.size() < 1) return;
[2446]149 typ = BT_ForeachList;
150 blkok = true;
[2483]151}
[2446]152else { // This is an integer or float loop
153 size_t l = args[1].length();
154 size_t p = args[1].find(':');
155 size_t pp = args[1].find('.');
156 bool fl = (pp < l) ? true : false; // Float loop or integer loop
157 if (p >= l) return; // Syntaxe error
158 string a1 = args[1].substr(0, p);
159 string aa = args[1].substr(p+1);
160 p = aa.find(':');
161 string a2, a3;
162 bool hasa3 = false;
163 if (p < aa.length() ) {
164 a2 = aa.substr(0,p);
165 a3 = aa.substr(p+1);
166 hasa3 = true;
167 }
168 else a2 = aa;
169 if (fl) {
170 typ = BT_ForeachFloat;
171 blkok = true;
172 f1 = atof(a1.c_str());
173 f2 = atof(a2.c_str());
174 if (hasa3) df = atof(a3.c_str());
175 else df = 1.;
176 }
177 else {
178 typ = BT_ForeachInt;
179 blkok = true;
180 i1 = atoi(a1.c_str());
181 i2 = atoi(a2.c_str());
182 if (hasa3) di = atoi(a3.c_str());
183 else di = 1;
184 }
185 }
186}
187
188/* --Methode-- */
189CommanderBloc::~CommanderBloc()
190{
[3581]191for(unsigned int k=0; k<blocs.size(); k++) delete blocs[k];
[2446]192}
193
194/* --Methode-- */
195void CommanderBloc::AddLine(string& line, string& kw)
196{
197 AddLine(line);
198 if (kw == "if") testlevel++;
199 else if (kw == "endif") testlevel--;
[4034]200 // bug trouve par JEC en Mai 2011 forinfile manquant ds la ligne suivante
201 else if ((kw == "for") || (kw == "foreach") || (kw == "forinfile")) looplevel++;
[2446]202 else if (kw == "end") looplevel--;
203 else if (kw == "defscript") scrdef = true;
204}
205
206/* --Methode-- */
[2518]207int CommanderBloc::Execute()
[2446]208{
209int k=0;
210char buff[32];
211int rcc = 0;
212
213int mxloop = _commander->GetMaxLoopLimit();
214
[2483]215if (typ == BT_ForeachLineInFile) { // foreach line in file loop
[2518]216 ifstream is(filename.c_str());
217 string line;
218 while (!is.eof()) {
219 rcc = 0;
[2796]220 line = "";
221 getline(is,line);
[4034]222 if (is.good()) { // bug signale par JEC en mai 2011 || is.eof()) {
[2518]223 rcc = ExecuteOnce(line);
[4034]224 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
[2796]225 else if (rcc == CMD_BREAK_RC) break;
[2518]226 }
227 }
[4034]228 rcc=0;
[2483]229}
[2518]230else if (typ == BT_ForeachList) { // foreach string loop
[3581]231 for(unsigned int k=0; k<strlist.size(); k++) {
[2518]232 rcc = ExecuteOnce(strlist[k]);
[4034]233 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
[2518]234 else if (rcc == CMD_BREAK_RC) break;
[4034]235 }
236 rcc = 0;
[2518]237}
238else if (typ == BT_ForeachInt) { // Integer loop
[2446]239 for(int i=i1; i<i2; i+=di) {
240 k++;
241 if ((mxloop>0) && (k > mxloop)) {
242 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
243 break;
244 }
[2518]245 sprintf(buff, "%d", i);
246 string lvv = buff;
247 rcc = ExecuteOnce(lvv);
[4034]248 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
[2518]249 else if (rcc == CMD_BREAK_RC) break;
[2446]250 }
[4034]251 rcc = 0;
[2518]252}
253else if (typ == BT_ForeachFloat) { // float loop
254 for(double f=f1; f<f2; f+=df) {
[2446]255 k++;
256 if ((mxloop>0) && (k > mxloop)) {
257 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
258 break;
259 }
[3577]260 string lvv = cval_dble2str(f);
[2518]261 rcc = ExecuteOnce(lvv);
[4034]262 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
[2518]263 else if (rcc == CMD_BREAK_RC) break;
[2446]264 }
[4034]265 rcc = 0;
[2518]266}
267return(rcc);
268}
[2446]269
[2518]270/* --Methode-- */
271int CommanderBloc::ExecuteOnce(string& lvv)
272{
[3581]273 unsigned int kj=0;
[2518]274 int kk=0;
275 int rcc = 0;
276 _commander->SetVar(varname, lvv);
277 for(kj=0; kj<bloclineid.size(); kj++) {
278 rcc = 0;
279 kk = bloclineid[kj];
280 if (kk > 0)
281 rcc = _commander->Interpret(lines[kk-1]);
282 else
283 rcc = blocs[-kk-1]->Execute();
[4034]284 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
[2518]285 if (rcc == CMD_BREAK_RC) break;
286 }
287 return rcc;
[2446]288}
289
290// ---------------------------------------------------------------
291// Classe CommanderScript
292// Definition et execution d'un script de Commander
293// script : Une liste de commande Commander - Lors de l'execution,
294// les variables-argument $# $0 $1 sont definies.
295// ---------------------------------------------------------------
296
297/*!
[2598]298 \internal
[2446]299 \class SOPHYA::CommanderScript
300 \ingroup SysTools
[2598]301 Class for internal use by class Commander to handle functions
[2446]302 or scripts
303*/
304
305class CommanderScript {
306public:
307 CommanderScript(Commander* piac, string const& name, string const& comm);
308 virtual ~CommanderScript();
309
310 void AddLine(string& line, string& kw);
311 virtual int Execute(vector<string>& args);
312
313 inline string& Name() { return mName; }
314 inline string& Comment() { return mComm; }
315 inline int& TestLevel() { return testlevel; }
316 inline int& LoopLevel() { return looplevel; }
317 inline bool CheckScript()
318 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)&&fgok); }
319
320protected:
321 Commander* _commander;
322 string mName;
323 string mComm;
324 vector<string> lines;
325 int testlevel; // niveau d'imbrication des if
326 int looplevel; // niveau d'imbrication des for/foreach
327 bool scrdef; // true -> commande defscript ds for/foreach
328 bool fgok; // Script name OK
329
330};
331
332/* --Methode-- */
333CommanderScript::CommanderScript(Commander* piac, string const& name,
334 string const& comm)
335{
336_commander = piac;
337testlevel = looplevel = 0;
338scrdef = false;
339mName = name;
340if (!isalpha(name[0])) fgok = false;
341else fgok = true;
342mComm = comm;
343}
344
345/* --Methode-- */
346CommanderScript::~CommanderScript()
347{
348}
349
350/* --Methode-- */
351void CommanderScript::AddLine(string& line, string& kw)
352{
353 if (kw == "if") testlevel++;
354 else if (kw == "endif") testlevel--;
[4034]355 // bug trouve par JEC en Mai 2011 forinfile manquant ds la ligne suivante
356 else if ((kw == "for") || (kw == "foreach") || (kw == "forinfile")) looplevel++;
[2446]357 else if (kw == "end") looplevel--;
358 else if (kw == "defscript") scrdef = true;
359 lines.push_back(line);
360}
361
362/* --Methode-- */
363int CommanderScript::Execute(vector<string>& args)
364{
[3581]365 int rcc=-2;
[2446]366 if (!CheckScript()) return(-1);
367 cout << " CommanderScript::Execute() - Executing script " << Name() << endl;
[3581]368 for(unsigned int k=0; k<lines.size(); k++) {
[2518]369 rcc = _commander->Interpret(lines[k]);
370 if ( (rcc == CMD_BREAKEXE_RC) || (rcc == CMD_RETURN_RC) ) break;
[2446]371 }
[2518]372 return(rcc);
[2446]373}
374
[2671]375
[2446]376// ------------------------------------------------------------
[2671]377// Classe CommandExeThr
378// ------------------------------------------------------------
379/*!
380 \internal
381 \class SOPHYA::CommandExeThr
382 \ingroup SysTools
383 Class for internal use by class Commander for command execution in separate threads.
[2943]384 The command execution is carried in method run() which has its own exception handling bloc.
[2671]385*/
386class CommandExeThr : public ZThread {
387public:
388 CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw,
389 vector<string>& args, string& toks);
390 virtual void run();
391 inline uint_8 Id() { return _id; }
392 inline bool IfDone() { return _fgdone; }
393 inline string& Tokens() { return _toks; }
394 inline string& Keyword() { return _keyw; }
395protected:
396 uint_8 _id;
397 CmdExecutor * _cmdex;
398 string _keyw, _toks;
399 vector<string> _args;
400 bool _fgdone;
401};
402
403/* --Methode-- */
404CommandExeThr::CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw,
405 vector<string>& args, string& toks)
406{
407 _id = id;
408 _cmdex = cmdex;
409 _keyw = keyw;
[2956]410 _args = args;
411 _args.erase(_args.end()-1);
[2671]412 _toks = toks;
413 for(size_t k=_toks.size()-1; k>0; k--)
414 if (_toks[k] == '&') { _toks[k] = ' '; break; }
415 _fgdone = false;
416}
417
418/* --Methode-- */
419void CommandExeThr::run()
420{
[2943]421 int rc = 0;
422 try {
423 rc = _cmdex->Execute(_keyw, _args, _toks);
424 }
425 catch (PThrowable& exc) {
426 cout << "CommandExeThr::run() Catched Exception Msg()= "
427 << exc.Msg() << endl;
428 rc = -77;
429 }
430 catch (std::exception& sex) {
431 cout << "CommandExeThr::run() Catched std::exception what()= "
432 << sex.what() << endl;
433 rc = -78;
434 }
435 catch (...) {
436 cout << "CommandExeThr::run() Catched unknown (...) exception " << endl;
437 rc = -79;
438 }
[2671]439 _fgdone = true;
440 setRC(rc);
441}
442
443// ------------------------------------------------------------
[2446]444// Classe Commander
445// ------------------------------------------------------------
446typedef void (* DlModuleInitEndFunction) ();
447
448/*!
[2598]449 \class Commander
[2446]450 \ingroup SysTools
[2598]451 \brief Simple command interpreter
452
453 This Simple command interpreter with c-shell like syntax
454 can be used to add scripting capabilities
455 to applications.
456
[2671]457 Although the interpreter has many limitations compared to
[2598]458 c-shell, or Tcl , it provides some interesting possibilities:
459
460 - Extended arithmetic operations (c-like and RPN)
461 - Simple and vector variables
462 - Script definition
[2943]463 - Command execution in separate threads
[2598]464 - Dynamic Load
465
466 \sa CmdExecutor CExpressionEvaluator RPNExpressionEvaluator
467
468 Usage example:
469 \code
470 #include "commander.h"
471 ...
472 Commander cmd;
473 char* ss[3] = {"foreach f ( AA bbb CCCC ddddd )", "echo $f" , "end"};
474 for(int k=0; k<3; k++) {
475 string line = ss[k];
476 cmd.Interpret(line);
477 }
478 \endcode
[2446]479*/
480
481#define _MAGENTA_ 1
482
483static Commander* cur_commander = NULL;
484/* --Methode-- */
[2955]485/*!
486 \brief Constructor. Initializes variable list and copies \c history.pic to \c hisold.pic
487 if \b fgsigstop == true , calls ZThread::ActivateExitOnSignal()
488*/
489Commander::Commander(bool fgsigzt)
[2446]490{
491system("cp history.pic hisold.pic");
492hist.open("history.pic");
493histon = true;
494trace = false; timing = false;
495gltimer = NULL;
[4034]496felevel_ = 0;
[3814]497SetMaxLoopLimit();
[2446]498mulinecmd = "";
499mulinefg = false;
500spromptmul = "Cmd> ";
501SetCurrentPrompt(spromptmul);
[2483]502SetDefaultPrompt(spromptmul);
[2446]503curscript = NULL;
504
[2483]505_xstatus = 0;
506 _retstr = "";
507
[2518]508// Controle du flot d'execution
509 fgexebrk = false;
510
[4034]511curtestresult_ = true;
512PushStack();
[2446]513
[2671]514// Pour la numerotation et l'identification des threads
515ThrId = 0;
516
[2473]517// Numero de help-groupe courant - Le premier groupe ajoute aura un gid = 1
518// gid = 0 n'existe pas : c'est le groupe de toutes les commandes
519cmdgrpid = 0;
[2446]520
[2466]521string grp = "Commander";
522string gdesc = "Basic (generic) interpreter (class SOPHYA::Commander) builtin commands";
523AddHelpGroup(grp, gdesc);
524
[2446]525string kw = "Commander";
526string usage;
527usage = ">>> (Commander) Interpreter's keywords : \n";
[2671]528usage += " > set varname string # To set a variable, $varname \n";
[2446]529usage += " > unset varname # clear variable definition \n";
[2518]530usage += " > rpneval varname RPNExpression # Reverse Polish Notation evaluation \n";
531usage += " > varname = ArithmeticExpression # C-like Expression evaluation \n";
532usage += " > varname = 'String' # Set variable vname \n";
533usage += " > var2words varname wordvarname [sep] # to break varname into words \n";
534usage += " > echo string # output string \n";
535usage += " > echo2file filename string # Append the string to the specified file \n";
536usage += " > alias name string # define a command alias \n";
537usage += " > foreach varname ( string-list ) # Loop \n";
538usage += " > for varname i1:i2[:di] # Integer loop \n";
[2446]539usage += " > for varname f1:f2[:df] # Float loop \n";
[2518]540usage += " > forinfile varname FileName # Loop over lines in file \n";
[2446]541usage += " > end # end loops \n";
542usage += " > if ( test ) then # Conditional test : a == != < > <= >= b \n";
543usage += " > else # Conditional \n";
544usage += " > endif # End of conditional if bloc \n";
[4034]545usage += " > break # exit from the current loop blocs \n";
546usage += " > breakall # exit all loop blocs \n";
[2446]547usage += " > return # Stops command execution from a file \n";
548usage += " > defscript endscript # Command script definition \n";
549usage += " > listvars # List of variable names and values \n";
550usage += " > listalias # List of alias names and values \n";
551usage += " > listcommands # List of all known commands \n";
552usage += " > listscripts # List of all known scripts \n";
553usage += " > clearcript # Clear a script definition \n";
[2671]554usage += " > thrlist # List of command execution threads (& as the last character) \n";
555usage += " > clearthrlist # Removes finished threads from the list \n";
[2955]556usage += " > killthr Id # Try to stop a given thread (ThrId=id) by sending SIGUSR1 \n";
557usage += " > cancelthr Id # Try to cancel a given thread (ThrId=id) \n";
[2671]558usage += " > waitthr # Waits until all active threads have finished (join()) \n";
[2446]559usage += " > exec filename # Execute commands from file \n";
[2518]560usage += " > help <command_name> # <command_name> usage info \n";
561usage += " > sleep nsec # sleep nsec seconds \n";
562usage += " > readstdin varname # reads a line from stdin into $varname \n";
[2446]563usage += " > timingon timingoff traceon traceoff \n";
564RegisterHelp(kw, usage, grp);
565
566kw = "RPNEvaluator";
567usage = " Reverse Polish Notation (HP calculator like) expression evaluation \n";
568usage += " >> Stack: \n";
569usage += " ... (4) (3) z=(2) y=(1) x=(0)=Stack.Top() \n";
570usage += " >> Examples: \n";
571usage += " - sin(PI/6): pi 6 / sin \n";
572usage += " - 1*2*...*5: 1 2 3 4 5 product \n";
573usage += " - x=x+y: x = $x $y * \n";
574usage += " >>> Stack operations : \n";
575usage += " print x<>y pop push (duplicate x) \n";
576usage += " >>> Constants (Cst pushed to stack): \n";
577usage += " pi e \n";
578usage += " >>> Arithmetic operators (x,y) --> x@y \n";
579usage += " + - * / % ( (int)y % (int)x )\n";
580usage += " >>> F(X): x --> F(x) \n";
581usage += " chs sqrt sq log log10 exp \n";
582usage += " fabs floor ceil \n";
583usage += " cos sin tan acos asin atan deg2rad rad2deg \n";
584usage += " >>> F(X,Y): (x,y) --> F(x,y) \n";
585usage += " pow atan2 \n";
586usage += " >>> F(): random number generators \n";
587usage += " rand (flat 0..1) norand (normal/gaussian) \n";
588usage += " >>> Stack sum/product/mean/sigma/sigma^2 \n";
589usage += " sum product mean sigma sigma2 sigmean (y->sigma x->mean) \n";
590RegisterHelp(kw, usage, grp);
591
592kw = "autoiniranf";
593usage = "> Automatic random number generator initialisation\n";
[3615]594usage += " by AutoInitRand(int lp) \n";
[2446]595usage += " Usage: autoiniranf";
596RegisterCommand(kw, usage, NULL, grp);
597
[2671]598kw = "CExpEvaluator";
599usage = "> Evaluation of C-like expression (used in V = C-like-Expression) \n";
600usage += " >>> Arithmetic operators, parenthesis ( + - * / ) \n";
601usage += " >>> Functions : sqrt fabs floor hypot \n";
602usage += " ... exp log log10 pow ; sinh cosh tanh \n";
603usage += " ... sin cos tan asin acos atan atan2 \n";
604usage += " ... rand01() randpm1() gaurand() \n";
605usage += " >>> Constants : Pi = M_PI E = M_E \n";
606usage += " Example: x = 5.*(2.+sin(0.3*Pi))";
607RegisterCommand(kw, usage, NULL, grp);
608
[2446]609kw = "shell execute";
610usage = "> shell command_string # Execute shell command\n";
611usage += "> cshell command_string # Execute cshell command\n";
612usage += "---Examples:\n";
613usage += " > shell ls\n";
614usage += " > cshell echo '$LD_LIBRARY_PATH'; map2cl -h; ls\n";
615usage += " > shell myfile.csh [arg1] [arg2] [...]\n";
616usage += " (where the first line of \"myfile.csh\" is \"#!/bin/csh\")\n";
617RegisterCommand(kw, usage, NULL, grp);
618
619
620AddInterpreter(this);
621curcmdi = this;
[2955]622if (fgsigzt) ZThread::ActivateExitOnSignal(SIGUSR1);
[2446]623}
624
625/* --Methode-- */
626Commander::~Commander()
627{
628hist.close();
629if (gltimer) { delete gltimer; gltimer = NULL; }
630Modmap::iterator it;
631for(it = modmap.begin(); it != modmap.end(); it++) {
632 string name = (*it).first + "_end";
633 DlModuleInitEndFunction fend = (*it).second->GetFunction(name);
634 if (fend) fend();
635 delete (*it).second;
636 }
637
638for(ScriptList::iterator sit = mScripts.begin();
639 sit != mScripts.end(); sit++) delete (*sit).second;
640
641if (cur_commander == this) cur_commander = NULL;
642}
643
644/* --Methode-- */
645Commander* Commander::GetInterpreter()
646{
647return(cur_commander);
648}
649
650/* --Methode-- */
[2598]651//! Returns the string \c Commander as the interpreter's name.
[2446]652string Commander::Name()
653{
654return("Commander");
655}
656
657/* --Methode-- */
[2598]658//! Add the \b grp help group with description \b desc.
[2466]659void Commander::AddHelpGroup(string& grp, string& desc)
[2446]660{
[2466]661 int gid;
662 CheckHelpGrp(grp, gid, desc);
663}
664
665/* --Methode-- */
[2598]666/*!
667 \brief Register a command executor associated with a given keyword.
668 \param keyw : keyword identifying the command
669 \param usage : the command help and usage information
670 \param ce : CmdExecutor pointer for this a command. The same object can be registered
671 multiple time for different commands.
672 \param grp : The help group corresponding to this command.
673*/
[2466]674void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string& grp)
675{
[2446]676if (!ce) {
677 RegisterHelp(keyw, usage, grp);
678 return;
679 }
[2466]680int gid;
681CheckHelpGrp(grp,gid);
[2446]682cmdex cme;
683cme.group = gid;
684cme.us = usage;
685cme.cex = ce;
686cmdexmap[keyw] = cme;
687}
688
689/* --Methode-- */
[2598]690/*!
691 \brief Register a help text.
692 \param keyw : help keyword
693 \param usage : help text
694 \param grp : help group
695*/
[2446]696void Commander::RegisterHelp(string& keyw, string& usage, string& grp)
697{
[2466]698int gid;
699CheckHelpGrp(grp,gid);
[2446]700cmdex cme;
701cme.group = gid;
702cme.us = usage;
703cme.cex = NULL;
704helpexmap[keyw] = cme;
705}
706
707/* --Methode-- */
[2466]708bool Commander::CheckHelpGrp(string& grp, int& gid, string& desc)
[2446]709{
[2466]710gid = 0;
[2446]711CmdHGroup::iterator it = cmdhgrp.find(grp);
712if (it == cmdhgrp.end()) {
[2466]713 cmdgrpid++; gid = cmdgrpid;
714 hgrpst hgs; hgs.gid = gid; hgs.desc = desc;
715 cmdhgrp[grp] = hgs;
716 return true;
[2446]717 }
[2466]718else {
719 if (desc.length() > 0) (*it).second.desc = desc;
720 gid = (*it).second.gid;
721 return false;
[2446]722}
[2466]723}
[2446]724
725
726/* --Methode-- */
[2598]727/*!
728 \brief Dynamic loader for modules
729
730 A module is a shared library extending the application functionalities.
731 Typically, a module adds new commands to the interpreter. Once loaded,
732 the module is activated (initialized) by calling a function with the
733 name \b modulename_init . This function should be declared extern C
734 to avoid C++ name mangling. A cleanup function \b modulename_end
735 is called by the Commander destructor.
736
737 \param fnameso : Shared library name containing the module functions
738 and classes.
739 \param name : Module name. This string is used to form module
740 initializer and cleanup function name \c name_init \c name_end
741*/
[2446]742void Commander::LoadModule(string& fnameso, string& name)
743{
744PDynLinkMgr * dynlink = new PDynLinkMgr(fnameso, false);
745if (dynlink == NULL) {
746 cerr << "Commander/LoadModule_Error: Pb opening SO " << fnameso << endl;
747 return;
748 }
749string fname = name + "_init";
750DlModuleInitEndFunction finit = dynlink->GetFunction(fname);
751if (!finit) {
752 cerr << "Commander/LoadModule_Error: Pb linking " << fname << endl;
753 return;
754 }
755cout << "Commander/LoadModule_Info: Initialisation module" << name
756 << " " << fname << "() ..." << endl;
757finit();
758modmap[name] = dynlink;
759return;
760}
761
762/* --Methode-- */
[2598]763//! Declare a new interpreter
[2446]764void Commander::AddInterpreter(CmdInterpreter * cl)
765{
766if (!cl) return;
767interpmap[cl->Name()] = cl;}
768
769/* --Methode-- */
[2943]770//! Select an interpreter by its name as the current interpreter.
[2446]771void Commander::SelInterpreter(string& name)
772{
773InterpMap::iterator it = interpmap.find(name);
774if (it == interpmap.end()) return;
775curcmdi = (*it).second;
776}
777
778
779
780/* Fonction */
781static string GetStringFrStdin(Commander* piac)
782{
783char buff[128];
784fgets(buff, 128, stdin);
785buff[127] = '\0';
786return((string)buff);
787}
788
789/* --Methode-- */
[2598]790/*!
[2671]791 \brief Method which has to be invoked to interpret a given command line or string.
[2598]792*/
[2446]793int Commander::Interpret(string& s)
794{
795int rc = 0;
796ScriptList::iterator sit;
797
[2671]798// Si le flag d'arret d'execution a ete positionne on returne avec le code
799// de BREAKEXECUTION
800if (fgexebrk) {
801 cout << " ===> Commander::Interpret() - STOP Execution (CMD_BREAKEXE_RC)" << endl;
802 fgexebrk = false; return CMD_BREAKEXE_RC;
803}
804
[2446]805// On saute de commandes vides
806size_t l;
807l = s.length();
808if (!mulinefg && (l < 1)) return(0);
809
810// On enregistre les commandes
811if (histon) hist << s << endl;
812
813if (s[0] == '#') return(0); // si c'est un commentaire
814
815// Logique de gestion des lignes suite
816// un \ en derniere position indique la presence d'une ligne suite
817size_t lnb = s.find_last_not_of(' ');
[3383]818if (lnb >= l) return(0); // il n'y a que des blancs
[2446]819if (s[lnb] == '\\' ) { // Lignes suite ...
820 mulinecmd += s.substr(0,lnb);
821 if (!mulinefg) {
822 spromptmul = GetCurrentPrompt();
823 SetCurrentPrompt("...? ");
824 mulinefg = true;
825 }
826 return(0);
827}
828
829if (mulinefg) { // Il y avait des lignes suite
830 s = mulinecmd + s;
831 l = s.length();
832 mulinecmd = "";
833 mulinefg = false;
834 SetCurrentPrompt(spromptmul);
835}
836
837// Removing leading blanks
838size_t p,q;
839
840// On enleve le dernier caractere, si celui-ci est \n
841if (s[l-1] == '\n') s[l-1] = '\0';
842p=s.find_first_not_of(" \t");
843if (p < l) s = s.substr(p);
844// >>>> Substitution d'alias (1er mot)
845CmdStrList::iterator it;
846p = 0;
847q = s.find_first_of(" \t");
848l = s.length();
849string w1 = (q < l) ? s.substr(p,q-p) : s.substr(p);
850it = mAliases.find(w1);
851if (it != mAliases.end()) {
852 s = (q < l) ? ((*it).second + s.substr(q)) : (*it).second ;
853 l = s.length();
854 p=s.find_first_not_of(" \t");
855 if (p < l) s = s.substr(p);
856 p = 0;
857 q = s.find_first_of(" ");
858 }
859
860// >>>> Separating keyword
861string toks,kw;
862if (q < l)
863 { kw = s.substr(p,q-p); toks = s.substr(q, l-q); }
864else { kw = s.substr(p,l-p); toks = ""; }
865
866// les mot-cle end else endif doivent etre le seul mot de la ligne
867if ( (kw == "end") || (kw == "else") || (kw == "endif") || (kw == "endscript") ) {
868 size_t ltk = toks.length();
869 if (toks.find_first_not_of(" \t") < ltk) {
870 cerr << "Commander::Interpret()/syntax error near end else endif endscript \n"
871 << "line: " << s << endl;
[2483]872 _xstatus = 91;
873 return(91);
[2446]874 }
875}
876
877// On verifie si on est en train de definir un script
878if (curscript) {
879 if (kw == "endscript") {
880 if (curscript->CheckScript()) {
881 sit = mScripts.find(curscript->Name());
882 if (sit != mScripts.end()) {
883 cout << "Commander::Interpret() replacing script "
884 << curscript->Name() << endl;
885 CommanderScript* scr = mScripts[curscript->Name()];
886 mScripts.erase(sit);
887 delete scr;
888 }
889 cout << "Commander::Interpret() Script " << curscript->Name()
890 << " defined successfully" << endl;
891 mScripts[curscript->Name()] = curscript;
892 SetCurrentPrompt("Cmd> ");
893 curscript = NULL;
[2483]894 _xstatus = 0;
[2446]895 return(0);
896 }
897 else {
898 cout << "Commander::Interpret() Error in Script " << curscript->Name()
899 << " definition " << endl;
900 SetCurrentPrompt("Cmd> ");
901 curscript = NULL;
[2483]902 _xstatus = 92;
903 return(92);
[2446]904 }
905 }
906 else curscript->AddLine(s, kw);
[2483]907 _xstatus = 0;
[2446]908 return(0);
909}
910// On verifie si nous sommes dans un bloc (for , foreach)
911if (CmdBlks.top() != NULL) { // On est dans un bloc
[4034]912 if ( (kw == "for") || (kw == "foreach") || (kw == "forinfile") ) felevel_++;
913 else if (kw == "end") felevel_--;
[2856]914
915 int rcbex = 0;
[4034]916 if (felevel_ == 0) { // Il faut executer le bloc
[2446]917 CommanderBloc* curb = CmdBlks.top();
918 CmdBlks.top() = curb->Parent();
919 SetCurrentPrompt("Cmd> ");
920 if (!curb->CheckBloc()) {
921 cerr << "Commander::Interpret()/syntax error - unbalenced if ... endif"
[2671]922 << " within for/foreach/forinfile bloc ! " << endl;
[2446]923 delete curb;
[2483]924 _xstatus = 93;
925 return(93);
[2446]926 }
927 // cout << " *DBG* Executing bloc " << endl;
928 bool ohv = histon;
929 histon = false;
[4034]930 if (curtestresult_) {
[2446]931 // We push also CommanderBloc and testresult on the stack
[4034]932 PushStack();
[2856]933 rcbex = curb->Execute();
[4034]934 // And then, pop CommanderBloc and TestResult from the corresponding stacks
[2446]935 PopStack(false);
936 }
[2483]937 SetCurrentPrompt(defprompt);
[2446]938 delete curb;
939 histon = ohv;
940 }
941 else CmdBlks.top()->AddLine(s, kw);
[2856]942 _xstatus = rcbex;
943 return(rcbex);
[2446]944}
945else if (kw == "end") {
[2671]946 cerr << "Commander::Interpret()/syntax error - end outside for/foreach/forinfile bloc \n"
[2446]947 << "line: " << s << endl;
[2483]948 _xstatus = 94;
949 return(94);
[2446]950}
951
952// Sommes-nous dans un bloc de test if then else
[4034]953if (TestsStack.top().tstlist.size() > 0) { // Nous sommes ds un bloc if
[2446]954 if (kw == "else") {
[4034]955 if ((*tresit_) & 2) {
[2446]956 cerr << "Commander::Interpret()/syntax error - multiple else in if bloc \n"
957 << "line: " << s << endl;
[2483]958 _xstatus = 95;
959 return(95);
[2446]960 }
961 else {
[4034]962 const char * npr = ((*tresit_)&1) ? "else-F> " : "else-T> ";
963 if ((*tresit_)&1) curtestresult_ = false;
[2446]964 SetCurrentPrompt(npr);
[4034]965 (*tresit_) |= 2;
[2483]966 _xstatus = 0;
[2446]967 return(0);
968 }
969 }
970 else if (kw == "endif") {
[4034]971 list<char>::iterator dbit = tresit_;
972 tresit_--;
973 TestsStack.top().tstlist.erase(dbit);
[2446]974 const char * npr = "Cmd> ";
[4034]975 if (TestsStack.top().tstlist.size() > 1) {
976 curtestresult_ = true;
[2446]977 list<char>::iterator it;
[4034]978 for(it=TestsStack.top().tstlist.begin(); it!=TestsStack.top().tstlist.end(); it++) {
[2446]979 // Si on n'est pas ds le else et le if est faux
[4034]980 if ( !((*it)&2) && !((*it)&1) ) curtestresult_ = false;
[2446]981 // Si on est ds else et le if etait vrai !
[4034]982 if ( ((*it)&2) && ((*it)&1) ) curtestresult_ = false;
983 if (!curtestresult_) break;
[2446]984 }
985
[4034]986 if (!((*tresit_)&2))
987 npr = ((*tresit_)&1) ? "if-T> " : "if-F> ";
[2446]988 else
[4034]989 npr = ((*tresit_)&1) ? "else-F> " : "else-T> ";
[2446]990 }
[4034]991 else curtestresult_ = true;
[2446]992 SetCurrentPrompt(npr);
[2483]993 _xstatus = 0;
[2446]994 return(0);
995 }
996}
997else if ((kw == "else") || (kw == "endif")) {
998 cerr << "Commander::Interpret()/syntax error - else,endif outside if bloc \n"
999 << "line: " << s << endl;
[2483]1000 _xstatus = 91;
1001 return(91);
[2446]1002}
1003
1004bool fgcont = true;
[4034]1005if (TestsStack.top().tstlist.size() > 0) { // Resultat de if ou else
[2446]1006 list<char>::iterator it;
[4034]1007 for(it=TestsStack.top().tstlist.begin(); it!=TestsStack.top().tstlist.end(); it++) {
[2446]1008 // Si on n'est pas ds le else et le if est faux
1009 if ( !((*it)&2) && !((*it)&1) ) fgcont = false;
1010 // Si on est ds else et le if etait vrai !
1011 if ( ((*it)&2) && ((*it)&1) ) fgcont = false;
1012 if (!fgcont) break;
1013 }
1014}
1015
[2483]1016if ((!fgcont) && (kw != "if")) {
1017 _xstatus = 0;
1018 return(0);
1019}
[2446]1020
1021
1022// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
[2518]1023if (kw == "break") return CMD_BREAK_RC;
[4034]1024if (kw == "breakall") return CMD_BREAKALL_RC;
[2483]1025else if (kw == "return") {
1026 _retstr = toks;
[2518]1027 return CMD_RETURN_RC;
[2483]1028}
[2446]1029
1030// Nous ne sommes donc pas dans un bloc .... Substitution de variables
1031string s2;
1032int rcs ;
1033
1034rcs = SubstituteVars(s, s2);
1035if (rcs) {
1036 cerr << "Commander::Interpret()/syntax error in SubstituteVars() \n"
1037 << "line: " << s << endl;
[2483]1038 _xstatus = 99;
1039 return(99);
[2446]1040}
1041// >>>> Separating keyword and tokens
1042vector<string> tokens;
[2518]1043vector<bool> qottoks;
[2446]1044/* decoupage en mots */
[2518]1045LineToWords(s2, kw, tokens, qottoks, toks, true);
[2446]1046
1047// Si c'est un for/foreach, on cree un nouveau bloc
[2483]1048if ((kw == "foreach") || (kw == "for") || (kw == "forinfile") ) {
[2446]1049 // cout << " *DBG* We got a foreach... " << endl;
1050 CommanderBloc* bloc = new CommanderBloc(this, CmdBlks.top(), kw, tokens);
1051 if (!bloc->CheckOK()) {
1052 cerr << "Commander::Interpret() for/foreach syntax Error ! " << endl;
1053 delete bloc;
[2483]1054 _xstatus = 91;
1055 return(91);
[2446]1056 }
[4034]1057 felevel_++;
[2446]1058 if (CmdBlks.top()) CmdBlks.top()->AddBloc(bloc);
1059 else SetCurrentPrompt("for...> ");
1060 CmdBlks.top() = bloc;
1061 // cout << " *DBG* New Bloc created ... " << endl;
1062 return(0);
1063 }
1064else if (kw == "if") { // Un test if
1065 bool restst = true;
1066 int rct = EvaluateTest(tokens, s, restst);
1067 if (rct) {
1068 cerr << "Commander::Interpret() if syntax Error ! " << "line: " << s << endl;
[2483]1069 _xstatus = 91;
1070 return(91);
[2446]1071 }
1072 char res_tst = (restst) ? 1 : 0;
[4034]1073 TestsStack.top().tstlist.push_back(res_tst);
1074 if (TestsStack.top().tstlist.size() == 1) tresit_ = TestsStack.top().tstlist.begin();
1075 else tresit_++;
[2446]1076 const char * npr = (restst) ? "if-T> " : "if-F> ";
1077 SetCurrentPrompt(npr);
1078}
1079else if ((tokens.size() > 0) && (tokens[0] == "=")) {
[2512]1080 // x = Expression
[2518]1081 if (qottoks[1]) { // decodage sous forme de chaine
1082 SetVariable(kw, tokens[1]);
[2512]1083 }
[2518]1084 else {
1085 try {
1086 double res = 0.;
1087 if (tokens.size() > 2) {
1088 string sex = tokens[1];
[3581]1089 for(unsigned int js=2; js<tokens.size(); js++) sex += tokens[js];
[2518]1090 CExpressionEvaluator cex(sex);
1091 res = cex.Value();
1092 }
1093 else {
1094 CExpressionEvaluator cex(tokens[1]);
1095 res = cex.Value();
1096 }
[3577]1097 string vv = cval_dble2str(res);
[2518]1098 SetVariable(kw, vv);
1099 }
1100 catch (CExprException& cexerr) {
1101 cerr << "Commander::Interpret() evaluation Error : \n " << "line: " << s
1102 << " \n Msg=" << cexerr.Msg() << endl;
1103 _xstatus = 98;
1104 return(98);
1105 }
[2446]1106 }
1107}
1108else if (kw == "defscript") { // definition de script
1109 if (tokens.size() > 0) {
1110 if (tokens.size() < 2) tokens.push_back("");
1111 curscript = new CommanderScript(this, tokens[0], tokens[1]);
1112 SetCurrentPrompt("Script...> ");
1113 return(0);
1114 }
1115 else {
1116 cerr << "Commander::Interpret() No script name in defscript" << "line: " << s << endl;
[2483]1117 _xstatus = 91;
1118 return(91);
[2446]1119 }
1120}
1121else {
1122 // Si c'est le nom d'un script
1123 sit = mScripts.find(kw);
1124 if (sit != mScripts.end()) {
1125 bool ohv = histon;
1126 histon = false;
1127 tokens.insert(tokens.begin(), kw);
1128 PushStack(tokens);
1129 (*sit).second->Execute(tokens);
1130 PopStack(true);
1131 histon = ohv;
1132 }
1133 // Execution de commandes
1134 else rc = ExecuteCommandLine(kw, tokens, toks);
[2483]1135 _xstatus = rc;
[2446]1136 return(rc);
1137}
1138// cout << "Commander::Do() DBG KeyW= " << kw << " NbArgs= " << tokens.size() << endl;
1139// for(int ii=0; ii<tokens.size(); ii++)
1140// cout << "arg[ " << ii << " ] : " << tokens[ii] << endl;
1141
1142return(0);
1143}
1144
[2943]1145//! Can be called asynchronously (from a separate thread) to break (halt) execution (in loops, scripts ...)
[2671]1146void Commander::StopExecution()
1147{
1148 fgexebrk = true;
1149}
[2446]1150
[2671]1151
[2446]1152/* --Methode-- */
1153int Commander::LineToWords(string& line, string& kw, vector<string>& tokens,
[2518]1154 vector<bool>& qottoks, string& toks, bool uq)
[2446]1155{
1156if (line.length() < 1) return(0);
1157int nw = 1;
1158size_t p = line.find_first_not_of(" ");
1159line = line.substr(p);
1160p = 0;
1161size_t q = line.find_first_of(" ");
1162size_t l = line.length();
1163
1164if (q < l)
1165 { kw = line.substr(p,q-p); toks = line.substr(q, l-q); }
1166else { kw = line.substr(p,l-p); toks = ""; }
1167
1168q = 0;
1169while (q < l) {
[2518]1170 bool swq = false; // true -> chaine delimite par ' ou "
[2446]1171 p = toks.find_first_not_of(" \t",q+1); // au debut d'un token
1172 if (p>=l) break;
1173 if ( uq && ((toks[p] == '\'') || (toks[p] == '"')) ) {
1174 q = toks.find(toks[p],p+1);
1175 if (q>=l) {
1176 cerr << "Commander::LineToWords/Syntax Error - Unbalenced quotes " << toks[p] << '.' << endl;
1177 return(-1);
1178 }
[2518]1179 p++; swq = true;
[2446]1180 }
1181 else {
1182 q = toks.find_first_of(" \t",p); // la fin du token;
1183 }
1184 string token = toks.substr(p,q-p);
[2518]1185 tokens.push_back(token);
1186 qottoks.push_back(swq);
1187 nw++;
[2446]1188 }
1189
1190return(nw);
1191}
1192
1193/* --Methode-- */
1194int Commander::SubstituteVars(string & s, string & s2)
1195// Variable substitution
1196{
1197
1198int iarr = -1; // index d'element de tableau
1199size_t p,q,q2,q3,l;
[2997]1200bool fgvarapp = false; // Si true, VarApp en priorite
[2446]1201
1202s2="";
1203p = 0;
1204l = s.length();
1205string vn, vv;
1206while (p < l) {
1207 iarr = -1;
[2997]1208 fgvarapp = false;
[2446]1209 q = s.find('$',p);
1210 if (q > l) break;
1211 q2 = s.find('\'',p);
1212 if ((q2 < l) && (q2 < q)) { // On saute la chaine delimitee par ' '
1213 q2 = s.find('\'',q2+1);
1214 if (q2 >= l) {
1215 cerr << " Syntax error - Unbalenced quotes !!! " << endl;
1216 return(1);
1217 }
1218 s2 += s.substr(p, q2-p+1);
1219 p = q2+1; continue;
1220 }
1221 // cout << "DBG: " << s2 << " p= " << p << " q= " << q << " L= " << l << endl;
1222 if ((q>0) && (s[q-1] == '\\')) { // Escape character \$
1223 s2 += (s.substr(p,q-1-p) + '$') ; p = q+1;
1224 continue;
1225 }
1226 if (q >= l-1) {
1227 cerr << " Syntax error - line ending with $ !!! " << endl;
1228 return(2);
1229 }
1230 vn = "";
1231 if ( s[q+1] == '{' ) { // Variable in the form ${name}
1232 q2 = s.find('}',q+1);
1233 if (q2 >= l) {
1234 cerr << " Syntax error - Unbalenced brace {} !!! " << endl;
1235 return(3);
1236 }
1237 vn = s.substr(q+2,q2-q-2);
1238 q2++;
[2997]1239 fgvarapp = true;
[2446]1240 }
1241 else if ( s[q+1] == '(' ) { // Variable in the form $(name)
1242 q2 = s.find(')',q+1);
1243 if (q2 >= l) {
1244 cerr << " Syntax error - Unbalenced parenthesis () !!! " << endl;
1245 return(3);
1246 }
1247 vn = s.substr(q+2,q2-q-2);
1248 q2++;
1249 }
1250 else if ( s[q+1] == '[' ) { // Variable in the form $[varname] -> This is $$varname
1251 q2 = s.find(']',q+1);
1252 if (q2 >= l) {
1253 cerr << " Syntax error - Unbalenced brace [] !!! " << endl;
1254 return(4);
1255 }
1256 vn = s.substr(q+2,q2-q-2);
[2483]1257 if (!Var2Str(vn, vv)) return(5);
[2446]1258 vn = vv;
1259 q2++;
1260 }
1261 else {
[2779]1262 if (s[q+1] == '#' ) q3 = q+2; // Variable in the form $#varname
1263 else q3 = q+1;
1264 q2 = s.find_first_of(" .:+-*/,[](){}&|!$\"'<>^%=#@\\",q3);
[2446]1265 if (q2 > l) q2 = l;
1266 q3 = q2;
1267 vn = s.substr(q+1, q2-q-1);
1268 // Si variable de type $varname[index] : element de tableau
1269 if ((q2 < l) && (s[q2] == '[') ) {
1270 q3 = s.find_first_of("]",q2+1);
1271 string sia = s.substr(q2+1, q3-q2-1);
1272 if (sia.length() < 1) {
1273 cerr << " Syntax error - in $varname[index] : $"
1274 << vn << "[" << sia <<"]" << endl;
1275 return(4);
1276 }
1277 if (isalpha(sia[0])) {
1278 string sia2;
[2483]1279 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
[2446]1280 cerr << " Syntax error - in $varname[index] : $"
1281 << vn << "[" << sia <<"]" << endl;
1282 return(4);
1283 }
1284 sia = sia2;
1285 }
1286 int rcdia = ctoi(sia.c_str(), &iarr);
1287 if (rcdia < 0) {
1288 cerr << " Syntax error - in $varname[iarr] : $"
1289 << vn << "[" << sia <<"]" << endl;
1290 return(4);
1291 }
1292 }
1293 }
[2997]1294 if (fgvarapp) {
1295 if (!GetVarApp(vn, vv))
1296 if (!Var2Str(vn, vv)) return(5);
1297 s2 += (s.substr(p, q-p) + vv);
1298 p = q2;
1299 }
1300 else if (iarr < 0) {
[2483]1301 if (!Var2Str(vn, vv)) return(5);
[2446]1302 s2 += (s.substr(p, q-p) + vv);
1303 p = q2;
1304 }
1305 else {
[2483]1306 if (! Var2Str(vn, iarr, vv) ) {
[2446]1307 cerr << " Substitution error - word index out of range in "
1308 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
1309 return(4);
1310 }
[2483]1311 else s2 += (s.substr(p, q-p) + vv);
[2446]1312 p = q3+1;
1313 }
1314}
1315if (p < l) s2 += s.substr(p);
1316
1317p = s2.find_first_not_of(" \t");
1318if (p < l) s2 = s2.substr(p);
1319
1320return(0);
1321}
1322
1323/* --Methode-- */
[2483]1324bool Commander::Var2Str(string const & vn, string & vv)
[2446]1325{
1326if (vn.length() < 1) {
[2518]1327 cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
[2446]1328 vv = ""; return(false);
1329}
1330// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1331int ka = 0;
[2483]1332char buff[32];
1333
[2446]1334if (vn == "#") {
1335 if (ArgsStack.empty()) {
[2518]1336 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
[2446]1337 << " ($" << vn << ")" << endl;
1338 vv = ""; return(false);
1339 }
1340 char buff[32];
1341 long an = ArgsStack.top().size();
[2518]1342 if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0
[2446]1343 sprintf(buff,"%ld", an);
1344 vv = buff; return(true);
1345}
[2518]1346else if (vn == "*") {
1347 if (ArgsStack.empty()) {
1348 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1349 << " ($" << vn << ")" << endl;
1350 vv = ""; return(false);
1351 }
1352 vv = ArgsStack.top()[0];
[3581]1353 for(unsigned int ssk=1; ssk<ArgsStack.top().size(); ssk++) vv += ArgsStack.top()[ssk];
[2518]1354 return(true);
1355}
[2446]1356else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1357 if (ArgsStack.empty()) {
[2518]1358 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
[2446]1359 << " ($" << vn << ")" << endl;
1360 vv = ""; return(false);
1361 }
[3581]1362 if ( (ka < 0) || (ka >= (int)ArgsStack.top().size()) ) {
[2518]1363 cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! "
[2446]1364 << " ($" << vn << ")" << endl;
1365 vv = ""; return(false);
1366 }
1367 vv = ArgsStack.top()[ka]; return(true);
1368}
1369else if (vn[0] == '#') { // Variable de type $#vname --> size(vname)
[2483]1370 CmdVarList::iterator it = variables.find(vn.substr(1));
1371 if (it == variables.end()) {
[2518]1372 cerr << " Commander::Var2Str/Error #vname Undefined variable "
[2446]1373 << vn << " ! " << endl;
1374 vv = ""; return(false);
1375 }
[2483]1376 sprintf(buff,"%d", (int)(*it).second.size());
[2446]1377 vv = buff; return(true);
[2483]1378}
1379else if (vn == "status") {
1380 sprintf(buff,"%d", _xstatus);
1381 vv = buff;
1382 return true;
1383}
[2518]1384else if ((vn == "retstr") || (vn == "retval")) {
[2483]1385 vv = _retstr;
1386 return true;
1387}
1388else { // Variable de l'interpreteur, ou de l'environnement application , env. global
1389 if (GetVar(vn, vv)) return true;
1390 else if (GetVarApp(vn, vv)) return true;
1391 else if (GetVarEnv(vn, vv)) return true;
1392 else {
[2518]1393 cerr << " Commander::Var2Str/Error Undefined variable "
[2446]1394 << vn << " ! " << endl;
[2483]1395 vv = ""; return false;
[2446]1396 }
1397}
1398
[2483]1399return false;
[2446]1400}
[2483]1401
[2446]1402/* --Methode-- */
[2483]1403bool Commander::SetVariable(string const & vn, string const & vv)
[2446]1404{
[2483]1405 // On verifie si le nom est de type vname[idx]
1406 size_t p,q,l;
1407 l = vn.length();
1408 p = vn.find('[');
1409 if (p < l) {
1410 q = vn.find(']');
1411 if (q != (l-1)) {
1412 cout << "Commander::Str2Var/SetVar() - Bad varname with []: "
1413 << vn << endl;
1414 return false;
1415 }
1416 string vna = vn.substr(0, p);
1417 string sia = vn.substr(p+1, q-(p+1));
1418 if (isalpha(sia[0])) {
1419 string sia2;
1420 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1421 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[index]:"
1422 << vn << endl;
1423 return false;
1424 }
1425 sia = sia2;
1426 }
1427 int iarr;
1428 int rcdia = ctoi(sia.c_str(), &iarr);
1429 if (rcdia < 0) {
1430 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[iarr]: "
1431 << vn << endl;
1432 return false;
1433 }
1434 return SetVar(vna, iarr, vv);
[2446]1435 }
[2483]1436 else {
1437 if (vn == "status") {
1438 _xstatus = atoi(vv.c_str());
1439 return true;
1440 }
1441 else if (vn == "retstr") {
1442 _retstr = vv;
1443 return true;
1444 }
1445 else return SetVar(vn, vv);
1446 }
[2446]1447}
1448
1449/* --Methode-- */
[2483]1450bool Commander::GetVar(string const & vn, string & vv)
[2446]1451{
[2483]1452 CmdVarList::iterator it = variables.find(vn);
1453 if (it == variables.end()) {
1454 vv = "";
1455 return false;
1456 }
1457 vv = (*it).second[0];
1458 if ((*it).second.size() > 1) {
[3581]1459 for(unsigned int k=1; k<(*it).second.size(); k++) {
[2483]1460 vv += ' '; vv += (*it).second[k];
1461 }
1462 }
1463 return true;
1464}
1465
1466/* --Methode-- */
1467bool Commander::GetVar(string const & vn, int idx, string & vv)
1468{
1469 vv = "";
1470 CmdVarList::iterator it = variables.find(vn);
1471 if (it == variables.end()) return false;
[3581]1472 if ((idx < 0) || (idx > (int)(*it).second.size()-1))
[2483]1473 return false;
1474 vv = (*it).second[idx];
1475 return true;
1476}
1477
1478/* --Methode-- */
1479bool Commander::GetVar(string const & vn, vector<string> & vv)
1480{
1481 vv.clear();
1482 // vv.erase(vv.begin(),vv.end());
1483 CmdVarList::iterator it = variables.find(vn);
1484 if (it == variables.end()) return false;
1485 vv = (*it).second;
1486 return true;
1487}
1488
1489/* --Methode-- */
1490bool Commander::SetVar(string const & vn, string const & val)
1491{
1492 if ( !CheckVarName(vn) ) {
1493 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
[2446]1494 return(false);
1495 }
[2483]1496 bool fg = false;
1497 vector<string> nouv;
1498 nouv.push_back(val);
1499 CmdVarList::iterator it = variables.find(vn);
1500 if (it == variables.end()) variables[vn] = nouv;
1501 else {
1502 (*it).second = nouv;
1503 fg = true;
1504 }
1505 return fg;
[2446]1506}
1507
1508/* --Methode-- */
[2483]1509bool Commander::SetVar(string const & vn, int idx, string const & val)
[2446]1510{
[2483]1511 if ( !CheckVarName(vn) ) {
1512 cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl;
[2446]1513 return(false);
1514 }
[2483]1515 if ((vn == "status") || (vn == "retstr")) {
1516 cerr << "Commander::SetVar(vn,idx,val) ERROR - special var status/retstr "
1517 << endl;
1518 return(false);
1519 }
1520 if (idx < 0) {
1521 cout << "Commander::SetVar(vn," << idx << ",...) Error idx < 0" << endl;
1522 return(false);
1523 }
1524 bool fg = false;
1525 CmdVarList::iterator it = variables.find(vn);
1526 if (it == variables.end()) {
1527 vector<string> nouv;
1528 for(int j=0; j<idx; j++) nouv.push_back("");
1529 nouv.push_back(val);
1530 variables[vn] = nouv;
1531 }
1532 else {
[3581]1533 if (idx >= (int)(*it).second.size())
[2512]1534 for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back("");
1535 (*it).second[idx] = val;
[2483]1536 fg = true;
1537 }
[2446]1538 return fg;
1539}
1540
1541/* --Methode-- */
[2483]1542bool Commander::SetVar(string const & vn, vector<string> const & val)
[2446]1543{
[2483]1544 if ( !CheckVarName(vn) ) {
1545 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
[2446]1546 return(false);
1547 }
[2483]1548 if ((vn == "status") || (vn == "retstr")) {
1549 cerr << "Commander::SetVar(vn, vector<string>) ERROR - special var status/retstr "
1550 << endl;
1551 return(false);
1552 }
1553 bool fg = false;
1554 CmdVarList::iterator it = variables.find(vn);
1555 if (it == variables.end()) variables[vn] = val;
1556 else {
1557 (*it).second = val;
1558 fg = true;
1559 }
1560 return fg;
[2446]1561}
1562
1563/* --Methode-- */
[2483]1564bool Commander::CheckVarName(string const & vn)
[2446]1565{
[2483]1566 size_t l,k;
1567 l = vn.length();
1568 if (l < 1) return false;
1569 if (!isalpha(vn[0])) return false;
1570 for(k=1; k<l; k++)
1571 if ((!isalnum(vn[k])) && (vn[k] != '_')) return false;
1572 return true;
1573}
1574
1575/* --Methode-- */
1576bool Commander::DeleteVar(string const & vn)
1577{
1578 CmdVarList::iterator it = variables.find(vn);
1579 if (it == variables.end()) {
1580 cerr << "Commander::DeleteVar() Var " << vn << " undefined!" << endl;
1581 return false;
1582 }
1583 variables.erase(it);
1584 return true;
1585}
1586
1587/* --Methode-- */
1588void Commander::ListVar()
1589{
1590 cout << " ---- Commander::ListVar() List of defined variables ---- "
[2446]1591 << endl;
[2483]1592 CmdVarList::iterator it;
1593 for(it = variables.begin(); it != variables.end(); it++) {
1594 string vn = (*it).first;
1595 int vs = (*it).second.size();
1596 cout << vn << " -> Size= " << vs << endl;
1597 }
[2446]1598 cout << "---------------------------------------------------------- "
1599 << endl;
1600}
1601
1602/* --Methode-- */
[2483]1603bool Commander::GetVarApp(string const & vn, string & vv)
1604{
1605 vv = "";
[2518]1606 // cout << " Commander::GetVarApp() Not available ! " << endl;
[2483]1607 return false;
1608}
1609
1610/* --Methode-- */
1611bool Commander::SetVarApp(string const & vn, string const & vv)
1612{
[2518]1613 // cout << " Commander::SetVarApp() Not available ! " << endl;
[2483]1614 return false;
1615}
1616
1617/* --Methode-- */
1618bool Commander::DeleteVarApp(string const & vn)
1619{
[2518]1620 // cout << " Commander::DeleteVarApp() Not available ! " << endl;
[2483]1621 return false;
1622}
1623
1624/* --Methode-- */
1625void Commander::ListVarApp()
1626{
[2518]1627 // cout << " Commander::ListVarApp() Not available ! " << endl;
[2483]1628 return;
1629}
1630
1631
1632/* --Methode-- */
1633bool Commander::GetVarEnv(string const & vn, string & vv)
1634{
[2518]1635 char* vev = getenv(vn.c_str());
1636 if (vev) {
1637 vv = vev;
1638 return true;
1639 }
1640 else {
1641 vv = "";
1642 return false;
1643 }
[2483]1644}
1645
1646/* --Methode-- */
1647bool Commander::SetVarEnv(string const & vn, string const & vv)
1648{
[2518]1649 string pev = vn;
1650 pev += '=';
1651 pev += vv;
[2887]1652// if defined(Linux) || defined(AIX)
[2532]1653// Reza - 28/04/2004
1654// putenv de Linux ne declare pas la variable char *string const
1655// On ne doit meme pas utiliser une variable automatique
1656// J'alloue donc un nouveau tableau - mais qui va le liberer ?
[2867]1657// Idem AIX , Reza Dec 2005
[2887]1658// Pb apparu avec g++ 4 sur darwin (Mac) - Jan 2006
1659// Je fais copie pour tout le monde
[2532]1660 char* bev = new char[pev.size()+1];
1661 strcpy(bev, pev.c_str());
1662 if (putenv(bev) == 0) return true;
[2887]1663// else
1664// if (putenv(pev.c_str()) == 0) return true;
1665// endif
[2518]1666 else return false;
[2483]1667}
1668
1669/* --Methode-- */
1670bool Commander::DeleteVarEnv(string const & vn)
1671{
[2518]1672 // cout << " Commander::DeleteVarEnv() Not available ! " << endl;
[2483]1673 return false;
1674}
1675
1676/* --Methode-- */
1677void Commander::ListVarEnv()
1678{
1679 cout << " Commander::ListVarEnv() Not available ! " << endl;
1680 return;
1681}
1682
1683
1684/* --Methode-- */
[2446]1685string Commander::GetTmpDir()
1686{
1687 return("/tmp");
1688}
1689
1690/* --Methode-- */
1691void Commander::SetCurrentPrompt(const char* pr)
1692{
1693 curprompt = pr;
1694}
1695
1696/* --Methode-- */
1697void Commander::ShowMessage(const char * msg, int att)
1698{
1699 cout << msg ;
1700}
1701
1702
1703
1704/* --Methode-- */
1705int Commander::EvaluateTest(vector<string> & args, string & line, bool & res)
1706{
1707 res = true;
1708 if ((args.size() != 6) || (args[5] != "then") ||
1709 (args[0] != "(") || (args[4] != ")") ) return(1);
1710 if (args[2] == "==") res = (args[1] == args[3]);
1711 else if (args[2] == "!=") res = (args[1] != args[3]);
1712 else if (args[2] == "<")
1713 res = (atof(args[1].c_str()) < atof(args[3].c_str()));
1714 else if (args[2] == ">")
1715 res = (atof(args[1].c_str()) > atof(args[3].c_str()));
1716 else if (args[2] == "<=")
1717 res = (atof(args[1].c_str()) <= atof(args[3].c_str()));
1718 else if (args[2] == ">=")
1719 res = (atof(args[1].c_str()) >= atof(args[3].c_str()));
1720 else return(2);
1721 return(0);
1722}
1723
1724
1725
1726/* --Methode-- */
[4034]1727void Commander::PushStack(vector<string>* pargs)
[2446]1728{
[4034]1729 // We push the argument list (args) on the stack if not NULL
1730 if (pargs != NULL) ArgsStack.push(*pargs);
[2446]1731 // We push also CommanderBloc and testresult on the stack
1732 CmdBlks.push(NULL);
[4034]1733 if (TestsStack.size()>0) {
1734 TestsStack.top().tstresit=tresit_;
1735 TestsStack.top().tstcurres=curtestresult_;
1736 }
1737 TstStatus tstat;
1738 tstat.tstcurres=curtestresult_;
1739 TestsStack.push(tstat);
[2446]1740}
1741
1742/* --Methode-- */
1743void Commander::PopStack(bool psta)
1744{
1745 // We remove the argument list (args) from the stack
1746 if (psta) ArgsStack.pop();
1747 // And CommanderBloc and TestResult from the corresponding stacks
1748 CommanderBloc* curb = CmdBlks.top();
1749 while (curb != NULL) {
1750 CommanderBloc* parb = curb->Parent();
1751 delete curb; curb = parb;
1752 }
1753 CmdBlks.pop();
1754 TestsStack.pop();
[4034]1755 tresit_=TestsStack.top().tstresit;
1756 curtestresult_=TestsStack.top().tstcurres;
[2446]1757}
1758
1759/* --Methode-- */
1760int Commander::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
1761{
1762int rc = 0;
1763
1764// >>>>>>>>>>> Commande d'interpreteur
1765if (kw == "help") {
1766 if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl;
1767 else {
1768 string kwh = "Commander";
1769 cout << GetUsage(kwh) << endl;
1770 }
1771 }
[2518]1772else if (kw == "sleep") {
1773 if (tokens.size() < 1) {
1774 cout << "Commander::Interpret() Usage: sleep nsec " << endl;
1775 return(1);
1776 }
1777 int nsec = atoi(tokens[0].c_str());
1778 cout << "Commander::Interpret() sleep " << nsec << " seconds" << endl;
1779 sleep(nsec);
1780}
[2446]1781
1782else if (kw == "set") {
[2518]1783 if (tokens.size() < 2) {
1784 cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl;
1785 return(1);
1786 }
1787
[2483]1788 if (tokens.size() == 2)
1789 SetVariable(tokens[0], tokens[1]);
1790 else {
[2518]1791 if ( (tokens[1] != "(") || (tokens[tokens.size()-1] != ")") ) {
1792 cout << "Commander::Interpret() Usage: set vecvar ( w1 w2 ... ) " << endl;
1793 return(1);
1794 }
1795 string vname = tokens[0];
1796 vector<string>::iterator vit;
1797 vit = tokens.begin(); tokens.erase(vit);
1798 vit = tokens.begin(); tokens.erase(vit);
1799 tokens.pop_back();
1800 SetVar(vname, tokens);
[2446]1801 }
[2483]1802 return 0;
1803}
[2518]1804else if (kw == "var2words") {
1805 if (tokens.size() < 2) {
1806 cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl;
1807 return(1);
[2446]1808 }
[2518]1809 char sep = ' ';
1810 if (tokens.size() > 2) sep = tokens[2][0];
1811 string vv;
1812 if (!GetVar(tokens[0], vv)) {
1813 cout << "Commander::Interpret() var2words/Error No variable with name " << tokens[0] << endl;
1814 return 2;
1815 }
1816 vector<string> vs;
1817 FillVStringFrString(vv, vs, sep);
1818 SetVar(tokens[1], vs);
1819}
[2446]1820else if (kw == "alias") {
1821 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: alias aliasname string" << endl; return(0); }
1822 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1823 cerr << "Commander::Interpret()/Error alias name should start with alphabetic" << endl;
[2518]1824 return(1);
[2483]1825 }
[2446]1826 string xx = tokens[1];
[3581]1827 for (unsigned int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
[2446]1828 mAliases[tokens[0]] = xx;
[2483]1829}
[2446]1830
[2483]1831else if ( (kw == "unset") || (kw == "clearvar") ) {
1832 if (tokens.size() < 1) {
1833 cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;
[2518]1834 return(1);
[2446]1835 }
[2483]1836 else DeleteVar(tokens[0]);
1837}
1838// Evaluation d'expression en notation polonaise inverse
[2512]1839else if (kw == "rpneval") {
1840 try {
1841 RPNExpressionEvaluator rpn(tokens, 1);
1842 double res = rpn.Value();
[3577]1843 string vv = cval_dble2str(res);
[2512]1844 SetVariable(tokens[0],vv);
1845 return 0;
1846 }
1847 catch (RPNExprException& rpnerr) {
1848 cerr << " rpneval: Syntax error - Msg=" << rpnerr.Msg()
1849 << " \n Line=" << toks << endl;
1850 return 98;
1851 }
[2446]1852}
1853else if (kw == "echo") {
[3581]1854 for (unsigned int ii=0; ii<tokens.size(); ii++)
[2446]1855 cout << tokens[ii] << " " ;
1856 cout << endl;
1857 }
1858else if (kw == "echo2file") {
1859 if (tokens.size() < 1) {
1860 cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;
[2518]1861 return(1);
[2446]1862 }
1863 ofstream ofs(tokens[0].c_str(), ios::app);
[3581]1864 for (unsigned int ii=1; ii<tokens.size(); ii++)
[2446]1865 ofs << tokens[ii] << " " ;
1866 ofs << endl;
1867 }
1868else if (kw == "readstdin") {
1869 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: readstdin varname" << endl; return(0); }
1870 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1871 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1872 return(0);
1873 }
1874 ShowMessage(">>> Reading From StdIn \n", _MAGENTA_);
1875 cout << tokens[0] << " ? " << endl;
1876 SetVar(tokens[0], GetStringFrStdin(this) );
1877 }
1878
[2914]1879else if (kw == "listvars" || kw == "listvar") ListVar();
[2446]1880else if (kw == "listalias") {
1881 cout << "Commander::Interpret() Alias List , AliasName = Value \n";
1882 CmdStrList::iterator it;
1883 for(it = mAliases.begin(); it != mAliases.end(); it++)
1884 cout << (*it).first << " = " << (*it).second << "\n";
1885 cout << endl;
1886 }
1887else if (kw == "listcommands") {
1888 cout << "---- Commander::Interpret() Command List ----- \n";
1889 CmdExmap::iterator it;
1890 int kc = 0;
1891 for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
1892 cout << (*it).first << " ";
1893 kc++;
1894 if (kc >= 5) { cout << "\n"; kc = 0; }
1895 }
1896 cout << endl;
1897 }
1898else if (kw == "listscripts") {
1899 cout << "---- Commander::Interpret() Script List ----- \n";
1900 for(ScriptList::iterator sit = mScripts.begin();
1901 sit != mScripts.end(); sit++)
1902 cout << " Script: " << (*sit).second->Name() << " - "
1903 << (*sit).second->Comment() << endl;
1904}
1905else if (kw == "clearscript") {
1906 if (tokens.size() < 1) {
1907 cout << "Commander::Interpret() Usage: clearscript scriptname" << endl;
1908 return(0);
1909 }
1910 ScriptList::iterator sit = mScripts.find(tokens[0]);
1911 if (sit == mScripts.end()) {
1912 cout << "Commander::Interpret() No script with name" << tokens[0] << endl;
1913 return(0);
1914 }
1915 else {
1916 delete (*sit).second;
1917 mScripts.erase(sit);
1918 cout << "Commander::Interpret() script " << tokens[0] << " cleared" << endl;
1919 return(0);
1920 }
1921}
[2671]1922//---------------------------------------------
1923//--- Commandes de gestion des threads ------
1924//---------------------------------------------
1925else if (kw == "thrlist") {
1926 ListThreads();
1927 return(0);
1928}
[2955]1929else if ( (kw == "killthr") || (kw == "cancelthr") ) {
1930 if (tokens.size() < 1) {
1931 cout << "Commander::Interpret() Usage: killthr/cancelthr thrid" << endl;
1932 return(0);
1933 }
[2671]1934 uint_8 id = atol(tokens[0].c_str());
[2955]1935 bool fgkill = false;
1936 if (kw == "killthr") fgkill = true;
1937 StopThr(id, fgkill);
[2671]1938 return (0);
1939}
1940else if (kw == "waitthr") {
1941 WaitThreads();
1942 return (0);
1943}
1944else if (kw == "cleanthrlist") {
1945 CleanThrList();
1946 return (0);
1947}
1948
[2446]1949else if (kw == "traceon") { cout << "Commander::Interpret() -> Trace ON mode " << endl; trace = true; }
1950else if (kw == "traceoff") { cout << "Commander::Interpret() -> Trace OFF mode " << endl; trace = false; }
1951else if (kw == "timingon") {
1952 cout << "Commander::Interpret() -> Timing ON mode " << endl;
1953 if (gltimer) delete gltimer; gltimer = new Timer("PIA-CmdInterpreter "); timing = true;
1954 }
1955else if (kw == "timingoff") {
1956 cout << "Commander::Interpret() -> Timing OFF mode " << endl;
1957 if (gltimer) delete gltimer; gltimer = NULL; timing = false;
1958 }
1959else if (kw == "exec") {
1960 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: exec filename" << endl; return(0); }
1961 ExecFile(tokens[0], tokens);
1962 }
1963else if (kw == "autoiniranf") {
[3615]1964 AutoInitRand(1);
[2446]1965 return(0);
1966}
1967else if (kw == "shell") {
1968 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: shell cmdline" << endl; return(0); }
1969 string cmd;
[3581]1970 for (unsigned int ii=0; ii<tokens.size(); ii++)
[2446]1971 cmd += (tokens[ii] + ' ');
1972 system(cmd.c_str());
1973 }
1974else if (kw == "cshell") {
1975 if(tokens.size()<1) {cout<<"Commander::Interpret() Usage: cshell cmdline"<<endl; return(0);}
1976 string cmd="";
[3581]1977 for(unsigned int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
[2446]1978 CShellExecute(cmd);
1979 }
1980
1981// Execution d'une commande enregistree
1982else rc = ExecuteCommand(kw, tokens, toks);
1983
1984if (timing) gltimer->Split();
1985return(rc);
1986}
1987
1988/* --Methode-- */
1989int Commander::ParseLineExecute(string& line, bool qw)
1990 // Si qw == true, on decoupe entre '' ou "" ou espaces
1991{
1992vector<string> tokens;
[2518]1993vector<bool> qottoks;
[2446]1994string kw, toks;
1995if (line.length() < 1) return(0);
[2518]1996LineToWords(line, kw, tokens, qottoks, toks, qw);
[2446]1997return(ExecuteCommand(kw, tokens, toks));
1998}
1999
2000/* --Methode-- */
2001int Commander::ExecuteCommand(string& keyw, vector<string>& args, string& toks)
2002{
2003 int rc = -1;
2004 CmdExmap::iterator it = cmdexmap.find(keyw);
2005 if (it == cmdexmap.end()) cout << "No such command : " << keyw << " ! " << endl;
2006 else {
[2671]2007 if ((*it).second.cex) {
2008 // Doit-on l'executer sous forme de thread separe ?
[2956]2009 if ( (args.size()>0) && (args[args.size()-1] == "&") ) {
2010 if ((*it).second.cex->IsThreadable(keyw) ) {
2011 ThrId++;
2012 CommandExeThr * thr =
2013 new CommandExeThr(ThrId, (*it).second.cex, keyw, args, toks);
2014 CmdThrExeList.push_back(thr);
2015 cout << " Commander::ExecuteCommand() : Thread execution of command " << keyw << endl;
2016 thr->start();
2017 if (CmdThrExeList.size() > 5) CleanThrList();
2018 rc = 0;
2019 }
2020 else {
2021 args.erase(args.end()-1);
2022 for(size_t k=toks.size()-1; k>0; k--)
2023 if (toks[k] == '&') { toks[k] = ' '; break; }
2024 cout << " Commander::ExecuteCommand() : Thread execution NOT available for" << keyw << endl;
2025 rc = (*it).second.cex->Execute(keyw, args, toks);
2026 }
[2671]2027 }
[2943]2028 else rc = (*it).second.cex->Execute(keyw, args, toks);
[2671]2029 }
[2446]2030 else cout << "Dont know how to execute " << keyw << " ? " << endl;
[2943]2031 }
[2446]2032 return(rc);
2033}
2034
2035/* --Methode-- */
2036int Commander::ExecFile(string& file, vector<string>& args)
2037{
[2856]2038char line_buff[1024];
[2446]2039FILE *fip;
[2518]2040int rcc = 0;
[2446]2041if ( (fip = fopen(file.c_str(),"r")) == NULL ) {
2042 if (file.find('.') >= file.length()) {
2043 cout << "Commander::Exec(): Error opening file " << file << endl;
2044 file += ".pic";
2045 cout << " Trying file " << file << endl;
2046 fip = fopen(file.c_str(),"r");
2047 }
2048 }
2049
2050if(fip == NULL) {
2051 cerr << "Commander::Exec() Error opening file " << file << endl;
2052 hist << "##! Commander::Exec() Error opening file " << file << endl;
2053 return(0);
2054 }
2055
2056// hist << "### Executing commands from " << file << endl;
2057PushStack(args);
2058if (trace) {
2059 ShowMessage("### Executing commands from ", _MAGENTA_);
2060 ShowMessage(file.c_str(), _MAGENTA_);
2061 ShowMessage("\n", _MAGENTA_);
2062 }
2063
2064bool ohv = histon;
2065histon = false;
[2856]2066while (fgets(line_buff,1023,fip) != NULL)
[2446]2067 {
2068 if (trace) ShowMessage(line_buff, _MAGENTA_);
2069 line_buff[strlen(line_buff)-1] = '\0'; /* LF/CR de la fin */
2070 string line(line_buff);
[2518]2071 rcc = Interpret(line);
2072 if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
[2446]2073 }
2074histon = ohv;
2075
2076// hist << "### End of Exec( " << file << " ) " << endl;
2077if (trace) {
2078 ShowMessage("### End of Exec( ", _MAGENTA_);
2079 ShowMessage(file.c_str(), _MAGENTA_);
2080 ShowMessage(" ) \n", _MAGENTA_);
2081 }
2082
2083PopStack(true);
2084
2085return(0);
2086}
2087
2088/* --Methode-- */
[2671]2089void Commander::ListThreads()
2090{
[2955]2091 cout << "--- Commander::ListThreads()- command execution threads NThread="
2092 << CmdThrExeList.size() << " ---" << endl;
[2671]2093 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2094 tit != CmdThrExeList.end(); tit++) {
2095 cout << "Id=" << (*tit)->Id();
[2955]2096 if ( (*tit)->IfRunning() ) cout << " Executing";
2097 else if ( (*tit)->IfDone() ) cout << " Finished , Rc= " << (*tit)->getRC();
2098 else cout << " Stopped/Canceled";
2099 cout << " (Cmd= " << (*tit)->Keyword() << " " << (*tit)->Tokens().substr(0,35);
2100 if ((*tit)->Tokens().length() > 35) cout << "... )" << endl;
2101 else cout << " )" << endl;
[2671]2102 }
2103}
2104/* --Methode-- */
[2955]2105void Commander::StopThr(uint_8 id, bool fgkill)
[2671]2106{
2107 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2108 tit != CmdThrExeList.end(); tit++) {
[2955]2109 if ( ((*tit)->Id() == id) && ((*tit)->IfRunning()) ) {
2110 if (fgkill) {
2111 (*tit)->kill(SIGUSR1);
2112 cout << "Commander::StopThr() Send signal SIGUSR1 to Thread Id= " << id << endl;
2113 }
2114 else {
2115 (*tit)->cancel();
2116 cout << "Commander::StopThr() Canceling Thread Id= " << id << endl;
2117 }
[2671]2118 return;
2119 }
2120 }
[2943]2121 cout << "Commander::StopThr()/Error: No active thread with Id= " << id << endl;
[2671]2122}
2123
2124/* --Methode-- */
2125void Commander::CleanThrList()
2126{
2127 cout << "---- Commander::CleanThrList() Cleaning thrlist ----- \n";
2128 list<CommandExeThr *> thrcopie;
[2955]2129 int ncl = 0;
[2671]2130 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2131 tit != CmdThrExeList.end(); tit++) {
[2955]2132 if ( ((*tit)->IfEnded() || (*tit)->IfStopped()) && (ncl < 3) ) {
[2671]2133 cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
2134 delete (*tit);
[2955]2135 ncl++;
[2671]2136 }
2137 else thrcopie.push_back((*tit));
2138 }
2139 CmdThrExeList = thrcopie;
2140 cout << " ... " << CmdThrExeList.size() << " threads still active " << endl;
2141}
2142
2143/* --Methode-- */
2144void Commander::WaitThreads()
2145{
2146 cout << "---- Commander::WaitThreads() Wait/Join command execution threads - NThread="
2147 << CmdThrExeList.size() << " ----- " << endl;
2148 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2149 tit != CmdThrExeList.end(); tit++) {
2150 try {
2151 if (! (*tit)->IfDone()) (*tit)->join();
2152 }
2153 catch (std::exception & e) {
2154 cout << " Commander::WaitThreads()/Exception msg= " << e.what() << endl;
2155 }
2156 cout << " Joined thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << endl;
2157 delete (*tit);
2158 }
2159 CmdThrExeList.erase(CmdThrExeList.begin(), CmdThrExeList.end());
2160}
2161
2162/* --Methode-- */
[2446]2163int Commander::CShellExecute(string cmd)
2164{
2165 if(cmd.size()<=0) return -1;
2166
2167 string fname = GetTmpDir(); fname += "cshell_exec_pia.csh";
2168
2169 string cmdrm = "rm -f " + fname;
2170 system(cmdrm.c_str());
2171
2172 FILE *fip = fopen(fname.c_str(),"w");
2173 if(fip==NULL) {
2174 cout << "Commander/CShellExecute_Error: fopen("<<fname<<") failed"<<endl;
2175 return -2;
2176 }
2177 fprintf(fip,"#!/bin/csh\n\n");
2178 fprintf(fip,"%s\n",cmd.c_str());
2179 fprintf(fip,"\nexit 0\n");
2180 fclose(fip);
2181
2182 cmd = "csh "; cmd += fname;
2183 system(cmd.c_str());
2184
2185 system(cmdrm.c_str());
2186
2187 return 0;
2188}
2189
2190static string* videstr = NULL;
2191/* --Methode-- */
2192string& Commander::GetUsage(const string& kw)
2193{
2194bool fndok = false;
2195CmdExmap::iterator it = cmdexmap.find(kw);
2196if (it == cmdexmap.end()) {
2197 it = helpexmap.find(kw);
2198 if (it != helpexmap.end()) fndok = true;
2199 }
2200 else fndok = true;
2201if (fndok) return( (*it).second.us );
2202// Keyword pas trouve
2203if (videstr == NULL) videstr = new string("");
2204*videstr = "Nothing known about " + kw + " ?? ";
2205return(*videstr);
2206
2207}
2208
2209
2210/* Les definitions suivantes doivent se trouver ds l'en-tete du fichier LaTeX
2211 \newcommand{\piacommand}[1]{
2212 \framebox{\bf \Large #1 } \index{#1} % (Command)
2213 }
2214
2215 \newcommand{\piahelpitem}[1]{
2216 \framebox{\bf \Large #1 } \index{#1} (Help item)
2217 }
2218
2219 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2220*/
2221
2222// Fonction qui remplace tout caractere non alphanumerique en Z
2223static void check_latex_reflabel(string & prl)
2224{
[3581]2225 for(unsigned int k=0; k<prl.length(); k++)
[2446]2226 if (! isalnum(prl[k]) ) prl[k] = 'Z';
2227}
[2466]2228
[2446]2229// Fonction qui remplace _ en \_
2230static string check_latex_underscore(string const & mot)
2231{
2232 string rs;
[3581]2233 for(unsigned int k=0; k<mot.length(); k++) {
[2466]2234 if (mot[k] == '_') rs += "\\_";
[2446]2235 else rs += mot[k];
2236 }
2237 return rs;
2238}
2239
2240/* --Methode-- */
[2943]2241/*!
2242 \brief Produces a LaTeX file containing the registered command helps
2243 The file \b fname is created and can be inserted into a LaTeX document
2244 in order to produce the list of registered commands and corresponding description
2245 texts.
2246 The LaTeX file should contain the following definitions:
2247\verbatim
2248 \newcommand{\piacommand}[1]{
2249 \framebox{\bf \Large #1 } \index{#1} % (Command)
2250 }
2251
2252 \newcommand{\piahelpitem}[1]{
2253 \framebox{\bf \Large #1 } \index{#1} (Help item)
2254 }
2255
2256 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2257
2258\endverbatim
2259*/
[2446]2260void Commander::HelptoLaTeX(string const & fname)
2261{
2262FILE *fip;
2263if ((fip = fopen(fname.c_str(), "w")) == NULL) {
2264 cout << "Commander::HelptoLaTex_Error: fopen( " << fname << endl;
2265 return;
2266 }
2267
2268fputs("% ----- Liste des groupes de Help ----- \n",fip);
2269fputs("List of {\\bf piapp} on-line Help groups: \n", fip);
2270fputs("\\begin{itemize} \n",fip);
2271string prl;
2272string mol;
2273CmdHGroup::iterator it;
2274for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2275 if ((*it).first == "All") continue;
2276 prl = (*it).first; check_latex_reflabel(prl);
2277 mol = check_latex_underscore((*it).first);
2278 fprintf(fip,"\\item {\\bf %s } (p. \\pageref{%s}) \n",
2279 mol.c_str(), prl.c_str());
2280}
2281
2282fputs("\\end{itemize} \n",fip);
2283
2284fputs("\\vspace*{10mm} \n",fip);
2285
2286CmdExmap::iterator ite;
2287fputs("% ----- Liste de toutes les commandes et help item ----- \n",fip);
2288fputs("\\vspace{5mm} \n",fip);
2289// fputs("\\begin{table}[h!] \n", fip);
2290fputs("\\begin{center} \n ", fip);
2291fputs("\\rule{2cm}{1mm} List of {\\bf piapp} Help items \\rule{2cm}{1mm} \\\\ \n", fip);
2292fputs("\\vspace{3mm} \n",fip);
2293fputs("\\begin{tabular}{llllll} \n", fip);
2294int kt = 0;
2295for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2296 prl = (*ite).first; check_latex_reflabel(prl);
2297 mol = check_latex_underscore((*ite).first);
2298 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2299 kt++;
2300 if (kt < 3) fputs(" & ", fip);
2301 else { fputs(" \\\\ \n", fip); kt = 0; }
2302 }
2303if (kt == 1) fputs(" & & & \\\\ \n", fip);
2304else if (kt == 2) fputs(" & \\\\ \n", fip);
2305fputs("\\end{tabular} \n", fip);
2306fputs("\\end{center} \n", fip);
2307//fputs("\\end{table} \n", fip);
2308fputs("\\newpage \n",fip);
2309
2310int gid;
2311for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
[2466]2312 gid = (*it).second.gid;
[2446]2313 if (gid == 0) continue;
2314 // fputs("\\begin{table}[h!] \n",fip);
2315 fputs("\\vspace{6mm} \n",fip);
2316 fputs("\\begin{center} \n ", fip);
[2466]2317 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
[2446]2318 (*it).first.c_str());
2319 fputs("\\vspace{3mm} \n",fip);
2320 fputs("\\begin{tabular}{llllll} \n", fip);
2321 kt = 0;
2322 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2323 if ((*ite).second.group != gid) continue;
2324 prl = (*ite).first; check_latex_reflabel(prl);
2325 mol = check_latex_underscore((*ite).first);
2326 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2327 kt++;
2328 if (kt < 3) fputs(" & ", fip);
2329 else { fputs(" \\\\ \n", fip); kt = 0; }
2330 }
2331 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2332 if ((*ite).second.group != gid) continue;
2333 prl = (*ite).first; check_latex_reflabel(prl);
2334 mol = check_latex_underscore((*ite).first);
2335 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2336 kt++;
2337 if (kt < 3) fputs(" & ", fip);
2338 else { fputs(" \\\\ \n", fip); kt = 0; }
2339 }
2340 if (kt == 1) fputs(" & & & \\\\ \n", fip);
2341 else if (kt == 2) fputs(" & \\\\ \n", fip);
2342 fputs("\\end{tabular} \n", fip);
2343 fputs("\\end{center} \n", fip);
2344 // fputs("\\end{table} \n",fip);
2345 // fputs("\\vspace{5mm} \n",fip);
2346}
2347// fputs("\\newline \n",fip);
2348
2349fputs("% ----- Liste des commandes dans chaque groupe ----- \n",fip);
2350fputs("\\newpage \n",fip);
2351
2352for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
[2466]2353 gid = (*it).second.gid;
[2446]2354 if (gid == 0) continue;
2355 prl = (*it).first; check_latex_reflabel(prl);
2356 fprintf(fip,"\\subsection{%s} \\label{%s} \n",
2357 (*it).first.c_str(), prl.c_str());
[2466]2358 if ((*it).second.desc.length() > 0)
2359 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
[2446]2360 fprintf(fip,"\\noindent \n");
2361 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2362 if ((*ite).second.group != gid) continue;
2363 prl = (*ite).first; check_latex_reflabel(prl);
2364 mol = check_latex_underscore((*ite).first);
2365 fprintf(fip,"\\piahelpitem{%s} \\label{%s} \n",
2366 mol.c_str(), prl.c_str());
2367 fputs("\\begin{verbatim} \n",fip);
2368 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2369 fputs("\\end{verbatim} \n",fip);
2370 }
2371 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2372 if ((*ite).second.group != gid) continue;
2373 prl = (*ite).first; check_latex_reflabel(prl);
2374 mol = check_latex_underscore((*ite).first);
2375 fprintf(fip,"\\piacommand{%s} \\label{%s} \n",
2376 mol.c_str(), prl.c_str());
2377 fputs("\\begin{verbatim} \n",fip);
2378 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2379 fputs("\\end{verbatim} \n",fip);
2380 }
2381}
2382
2383fclose(fip);
[2466]2384cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
2385
[2446]2386return;
2387}
2388
2389
[2483]2390} // End of namespace SOPHYA
[2446]2391
Note: See TracBrowser for help on using the repository browser.