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

Last change on this file since 4040 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
Line 
1#include "sopnamsp.h"
2#include "commander.h"
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <ctype.h>
8#include <math.h>
9#include <signal.h>
10
11#include "strutil.h"
12#include "strutilxx.h"
13#include "cexpre.h"
14#include "rpneval.h"
15#include "srandgen.h"
16#include "zthread.h"
17
18
19namespace SOPHYA {
20
21//--------------------------------------------------
22// Pour ecrire une valeur double sous forme de string
23// sans perte de precision, et si possible de maniere
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: }
38char * cval_dble2str(double v)
39{
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;
53}
54//--------------------------------------------------
55
56// Differents code de retour specifiques
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
62
63// ------------------------------------------------------------
64// Bloc de commandes (Foreach, ...)
65// Classe CommanderBloc
66// ------------------------------------------------------------
67/*!
68 \internal
69 \class SOPHYA::CommanderBloc
70 \ingroup SysTools
71 Class for internal use by class Commander to handle loops
72*/
73class CommanderBloc {
74public:
75 enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat,
76 BT_ForeachLineInFile };
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()); }
87
88 // Execution complete du bloc (boucle)
89 int Execute();
90 // Execution pour un element de bloc
91 int ExecuteOnce(string& lvv);
92
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;
104 string filename; // forinfile bloc
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;
129if ((kw != "foreach") && (kw != "for") && (kw != "forinfile")) return;
130if (!piac->CheckVarName(args[0])) return;
131varname = args[0];
132
133//if (isalpha((int)args[1][0]) ) { This is a foreach bloc with string list
134if (kw == "forinfile") {
135 filename = args[1];
136 typ = BT_ForeachLineInFile;
137 blkok = true;
138}
139else if (kw == "foreach" ) { // This is a foreach bloc with string list
140 if ( (args[1] == "(") && (args[args.size()-1] == ")") ) {
141 // foreach varname ( w1 w2 w3 ... )
142 for(unsigned int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
143 }
144 else {
145 // foreach varname WordVectorName
146 if (!piac->GetVar(args[1], strlist)) return;
147 }
148 if (strlist.size() < 1) return;
149 typ = BT_ForeachList;
150 blkok = true;
151}
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{
191for(unsigned int k=0; k<blocs.size(); k++) delete blocs[k];
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--;
200 // bug trouve par JEC en Mai 2011 forinfile manquant ds la ligne suivante
201 else if ((kw == "for") || (kw == "foreach") || (kw == "forinfile")) looplevel++;
202 else if (kw == "end") looplevel--;
203 else if (kw == "defscript") scrdef = true;
204}
205
206/* --Methode-- */
207int CommanderBloc::Execute()
208{
209int k=0;
210char buff[32];
211int rcc = 0;
212
213int mxloop = _commander->GetMaxLoopLimit();
214
215if (typ == BT_ForeachLineInFile) { // foreach line in file loop
216 ifstream is(filename.c_str());
217 string line;
218 while (!is.eof()) {
219 rcc = 0;
220 line = "";
221 getline(is,line);
222 if (is.good()) { // bug signale par JEC en mai 2011 || is.eof()) {
223 rcc = ExecuteOnce(line);
224 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
225 else if (rcc == CMD_BREAK_RC) break;
226 }
227 }
228 rcc=0;
229}
230else if (typ == BT_ForeachList) { // foreach string loop
231 for(unsigned int k=0; k<strlist.size(); k++) {
232 rcc = ExecuteOnce(strlist[k]);
233 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
234 else if (rcc == CMD_BREAK_RC) break;
235 }
236 rcc = 0;
237}
238else if (typ == BT_ForeachInt) { // Integer loop
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 }
245 sprintf(buff, "%d", i);
246 string lvv = buff;
247 rcc = ExecuteOnce(lvv);
248 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
249 else if (rcc == CMD_BREAK_RC) break;
250 }
251 rcc = 0;
252}
253else if (typ == BT_ForeachFloat) { // float loop
254 for(double f=f1; f<f2; f+=df) {
255 k++;
256 if ((mxloop>0) && (k > mxloop)) {
257 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
258 break;
259 }
260 string lvv = cval_dble2str(f);
261 rcc = ExecuteOnce(lvv);
262 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
263 else if (rcc == CMD_BREAK_RC) break;
264 }
265 rcc = 0;
266}
267return(rcc);
268}
269
270/* --Methode-- */
271int CommanderBloc::ExecuteOnce(string& lvv)
272{
273 unsigned int kj=0;
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();
284 if ((rcc == CMD_BREAKEXE_RC) || (rcc == CMD_BREAKALL_RC)) return rcc;
285 if (rcc == CMD_BREAK_RC) break;
286 }
287 return rcc;
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/*!
298 \internal
299 \class SOPHYA::CommanderScript
300 \ingroup SysTools
301 Class for internal use by class Commander to handle functions
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--;
355 // bug trouve par JEC en Mai 2011 forinfile manquant ds la ligne suivante
356 else if ((kw == "for") || (kw == "foreach") || (kw == "forinfile")) looplevel++;
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{
365 int rcc=-2;
366 if (!CheckScript()) return(-1);
367 cout << " CommanderScript::Execute() - Executing script " << Name() << endl;
368 for(unsigned int k=0; k<lines.size(); k++) {
369 rcc = _commander->Interpret(lines[k]);
370 if ( (rcc == CMD_BREAKEXE_RC) || (rcc == CMD_RETURN_RC) ) break;
371 }
372 return(rcc);
373}
374
375
376// ------------------------------------------------------------
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.
384 The command execution is carried in method run() which has its own exception handling bloc.
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;
410 _args = args;
411 _args.erase(_args.end()-1);
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{
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 }
439 _fgdone = true;
440 setRC(rc);
441}
442
443// ------------------------------------------------------------
444// Classe Commander
445// ------------------------------------------------------------
446typedef void (* DlModuleInitEndFunction) ();
447
448/*!
449 \class Commander
450 \ingroup SysTools
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
457 Although the interpreter has many limitations compared to
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
463 - Command execution in separate threads
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
479*/
480
481#define _MAGENTA_ 1
482
483static Commander* cur_commander = NULL;
484/* --Methode-- */
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)
490{
491system("cp history.pic hisold.pic");
492hist.open("history.pic");
493histon = true;
494trace = false; timing = false;
495gltimer = NULL;
496felevel_ = 0;
497SetMaxLoopLimit();
498mulinecmd = "";
499mulinefg = false;
500spromptmul = "Cmd> ";
501SetCurrentPrompt(spromptmul);
502SetDefaultPrompt(spromptmul);
503curscript = NULL;
504
505_xstatus = 0;
506 _retstr = "";
507
508// Controle du flot d'execution
509 fgexebrk = false;
510
511curtestresult_ = true;
512PushStack();
513
514// Pour la numerotation et l'identification des threads
515ThrId = 0;
516
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;
520
521string grp = "Commander";
522string gdesc = "Basic (generic) interpreter (class SOPHYA::Commander) builtin commands";
523AddHelpGroup(grp, gdesc);
524
525string kw = "Commander";
526string usage;
527usage = ">>> (Commander) Interpreter's keywords : \n";
528usage += " > set varname string # To set a variable, $varname \n";
529usage += " > unset varname # clear variable definition \n";
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";
539usage += " > for varname f1:f2[:df] # Float loop \n";
540usage += " > forinfile varname FileName # Loop over lines in file \n";
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";
545usage += " > break # exit from the current loop blocs \n";
546usage += " > breakall # exit all loop blocs \n";
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";
554usage += " > thrlist # List of command execution threads (& as the last character) \n";
555usage += " > clearthrlist # Removes finished threads from the list \n";
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";
558usage += " > waitthr # Waits until all active threads have finished (join()) \n";
559usage += " > exec filename # Execute commands from file \n";
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";
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";
594usage += " by AutoInitRand(int lp) \n";
595usage += " Usage: autoiniranf";
596RegisterCommand(kw, usage, NULL, grp);
597
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
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;
622if (fgsigzt) ZThread::ActivateExitOnSignal(SIGUSR1);
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-- */
651//! Returns the string \c Commander as the interpreter's name.
652string Commander::Name()
653{
654return("Commander");
655}
656
657/* --Methode-- */
658//! Add the \b grp help group with description \b desc.
659void Commander::AddHelpGroup(string& grp, string& desc)
660{
661 int gid;
662 CheckHelpGrp(grp, gid, desc);
663}
664
665/* --Methode-- */
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*/
674void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string& grp)
675{
676if (!ce) {
677 RegisterHelp(keyw, usage, grp);
678 return;
679 }
680int gid;
681CheckHelpGrp(grp,gid);
682cmdex cme;
683cme.group = gid;
684cme.us = usage;
685cme.cex = ce;
686cmdexmap[keyw] = cme;
687}
688
689/* --Methode-- */
690/*!
691 \brief Register a help text.
692 \param keyw : help keyword
693 \param usage : help text
694 \param grp : help group
695*/
696void Commander::RegisterHelp(string& keyw, string& usage, string& grp)
697{
698int gid;
699CheckHelpGrp(grp,gid);
700cmdex cme;
701cme.group = gid;
702cme.us = usage;
703cme.cex = NULL;
704helpexmap[keyw] = cme;
705}
706
707/* --Methode-- */
708bool Commander::CheckHelpGrp(string& grp, int& gid, string& desc)
709{
710gid = 0;
711CmdHGroup::iterator it = cmdhgrp.find(grp);
712if (it == cmdhgrp.end()) {
713 cmdgrpid++; gid = cmdgrpid;
714 hgrpst hgs; hgs.gid = gid; hgs.desc = desc;
715 cmdhgrp[grp] = hgs;
716 return true;
717 }
718else {
719 if (desc.length() > 0) (*it).second.desc = desc;
720 gid = (*it).second.gid;
721 return false;
722}
723}
724
725
726/* --Methode-- */
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*/
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-- */
763//! Declare a new interpreter
764void Commander::AddInterpreter(CmdInterpreter * cl)
765{
766if (!cl) return;
767interpmap[cl->Name()] = cl;}
768
769/* --Methode-- */
770//! Select an interpreter by its name as the current interpreter.
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-- */
790/*!
791 \brief Method which has to be invoked to interpret a given command line or string.
792*/
793int Commander::Interpret(string& s)
794{
795int rc = 0;
796ScriptList::iterator sit;
797
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
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(' ');
818if (lnb >= l) return(0); // il n'y a que des blancs
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;
872 _xstatus = 91;
873 return(91);
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;
894 _xstatus = 0;
895 return(0);
896 }
897 else {
898 cout << "Commander::Interpret() Error in Script " << curscript->Name()
899 << " definition " << endl;
900 SetCurrentPrompt("Cmd> ");
901 curscript = NULL;
902 _xstatus = 92;
903 return(92);
904 }
905 }
906 else curscript->AddLine(s, kw);
907 _xstatus = 0;
908 return(0);
909}
910// On verifie si nous sommes dans un bloc (for , foreach)
911if (CmdBlks.top() != NULL) { // On est dans un bloc
912 if ( (kw == "for") || (kw == "foreach") || (kw == "forinfile") ) felevel_++;
913 else if (kw == "end") felevel_--;
914
915 int rcbex = 0;
916 if (felevel_ == 0) { // Il faut executer le bloc
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"
922 << " within for/foreach/forinfile bloc ! " << endl;
923 delete curb;
924 _xstatus = 93;
925 return(93);
926 }
927 // cout << " *DBG* Executing bloc " << endl;
928 bool ohv = histon;
929 histon = false;
930 if (curtestresult_) {
931 // We push also CommanderBloc and testresult on the stack
932 PushStack();
933 rcbex = curb->Execute();
934 // And then, pop CommanderBloc and TestResult from the corresponding stacks
935 PopStack(false);
936 }
937 SetCurrentPrompt(defprompt);
938 delete curb;
939 histon = ohv;
940 }
941 else CmdBlks.top()->AddLine(s, kw);
942 _xstatus = rcbex;
943 return(rcbex);
944}
945else if (kw == "end") {
946 cerr << "Commander::Interpret()/syntax error - end outside for/foreach/forinfile bloc \n"
947 << "line: " << s << endl;
948 _xstatus = 94;
949 return(94);
950}
951
952// Sommes-nous dans un bloc de test if then else
953if (TestsStack.top().tstlist.size() > 0) { // Nous sommes ds un bloc if
954 if (kw == "else") {
955 if ((*tresit_) & 2) {
956 cerr << "Commander::Interpret()/syntax error - multiple else in if bloc \n"
957 << "line: " << s << endl;
958 _xstatus = 95;
959 return(95);
960 }
961 else {
962 const char * npr = ((*tresit_)&1) ? "else-F> " : "else-T> ";
963 if ((*tresit_)&1) curtestresult_ = false;
964 SetCurrentPrompt(npr);
965 (*tresit_) |= 2;
966 _xstatus = 0;
967 return(0);
968 }
969 }
970 else if (kw == "endif") {
971 list<char>::iterator dbit = tresit_;
972 tresit_--;
973 TestsStack.top().tstlist.erase(dbit);
974 const char * npr = "Cmd> ";
975 if (TestsStack.top().tstlist.size() > 1) {
976 curtestresult_ = true;
977 list<char>::iterator it;
978 for(it=TestsStack.top().tstlist.begin(); it!=TestsStack.top().tstlist.end(); it++) {
979 // Si on n'est pas ds le else et le if est faux
980 if ( !((*it)&2) && !((*it)&1) ) curtestresult_ = false;
981 // Si on est ds else et le if etait vrai !
982 if ( ((*it)&2) && ((*it)&1) ) curtestresult_ = false;
983 if (!curtestresult_) break;
984 }
985
986 if (!((*tresit_)&2))
987 npr = ((*tresit_)&1) ? "if-T> " : "if-F> ";
988 else
989 npr = ((*tresit_)&1) ? "else-F> " : "else-T> ";
990 }
991 else curtestresult_ = true;
992 SetCurrentPrompt(npr);
993 _xstatus = 0;
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;
1000 _xstatus = 91;
1001 return(91);
1002}
1003
1004bool fgcont = true;
1005if (TestsStack.top().tstlist.size() > 0) { // Resultat de if ou else
1006 list<char>::iterator it;
1007 for(it=TestsStack.top().tstlist.begin(); it!=TestsStack.top().tstlist.end(); it++) {
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
1016if ((!fgcont) && (kw != "if")) {
1017 _xstatus = 0;
1018 return(0);
1019}
1020
1021
1022// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
1023if (kw == "break") return CMD_BREAK_RC;
1024if (kw == "breakall") return CMD_BREAKALL_RC;
1025else if (kw == "return") {
1026 _retstr = toks;
1027 return CMD_RETURN_RC;
1028}
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;
1038 _xstatus = 99;
1039 return(99);
1040}
1041// >>>> Separating keyword and tokens
1042vector<string> tokens;
1043vector<bool> qottoks;
1044/* decoupage en mots */
1045LineToWords(s2, kw, tokens, qottoks, toks, true);
1046
1047// Si c'est un for/foreach, on cree un nouveau bloc
1048if ((kw == "foreach") || (kw == "for") || (kw == "forinfile") ) {
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;
1054 _xstatus = 91;
1055 return(91);
1056 }
1057 felevel_++;
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;
1069 _xstatus = 91;
1070 return(91);
1071 }
1072 char res_tst = (restst) ? 1 : 0;
1073 TestsStack.top().tstlist.push_back(res_tst);
1074 if (TestsStack.top().tstlist.size() == 1) tresit_ = TestsStack.top().tstlist.begin();
1075 else tresit_++;
1076 const char * npr = (restst) ? "if-T> " : "if-F> ";
1077 SetCurrentPrompt(npr);
1078}
1079else if ((tokens.size() > 0) && (tokens[0] == "=")) {
1080 // x = Expression
1081 if (qottoks[1]) { // decodage sous forme de chaine
1082 SetVariable(kw, tokens[1]);
1083 }
1084 else {
1085 try {
1086 double res = 0.;
1087 if (tokens.size() > 2) {
1088 string sex = tokens[1];
1089 for(unsigned int js=2; js<tokens.size(); js++) sex += tokens[js];
1090 CExpressionEvaluator cex(sex);
1091 res = cex.Value();
1092 }
1093 else {
1094 CExpressionEvaluator cex(tokens[1]);
1095 res = cex.Value();
1096 }
1097 string vv = cval_dble2str(res);
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 }
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;
1117 _xstatus = 91;
1118 return(91);
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);
1135 _xstatus = rc;
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
1145//! Can be called asynchronously (from a separate thread) to break (halt) execution (in loops, scripts ...)
1146void Commander::StopExecution()
1147{
1148 fgexebrk = true;
1149}
1150
1151
1152/* --Methode-- */
1153int Commander::LineToWords(string& line, string& kw, vector<string>& tokens,
1154 vector<bool>& qottoks, string& toks, bool uq)
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) {
1170 bool swq = false; // true -> chaine delimite par ' ou "
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 }
1179 p++; swq = true;
1180 }
1181 else {
1182 q = toks.find_first_of(" \t",p); // la fin du token;
1183 }
1184 string token = toks.substr(p,q-p);
1185 tokens.push_back(token);
1186 qottoks.push_back(swq);
1187 nw++;
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;
1200bool fgvarapp = false; // Si true, VarApp en priorite
1201
1202s2="";
1203p = 0;
1204l = s.length();
1205string vn, vv;
1206while (p < l) {
1207 iarr = -1;
1208 fgvarapp = false;
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++;
1239 fgvarapp = true;
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);
1257 if (!Var2Str(vn, vv)) return(5);
1258 vn = vv;
1259 q2++;
1260 }
1261 else {
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);
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;
1279 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
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 }
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) {
1301 if (!Var2Str(vn, vv)) return(5);
1302 s2 += (s.substr(p, q-p) + vv);
1303 p = q2;
1304 }
1305 else {
1306 if (! Var2Str(vn, iarr, vv) ) {
1307 cerr << " Substitution error - word index out of range in "
1308 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
1309 return(4);
1310 }
1311 else s2 += (s.substr(p, q-p) + vv);
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-- */
1324bool Commander::Var2Str(string const & vn, string & vv)
1325{
1326if (vn.length() < 1) {
1327 cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
1328 vv = ""; return(false);
1329}
1330// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1331int ka = 0;
1332char buff[32];
1333
1334if (vn == "#") {
1335 if (ArgsStack.empty()) {
1336 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1337 << " ($" << vn << ")" << endl;
1338 vv = ""; return(false);
1339 }
1340 char buff[32];
1341 long an = ArgsStack.top().size();
1342 if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0
1343 sprintf(buff,"%ld", an);
1344 vv = buff; return(true);
1345}
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];
1353 for(unsigned int ssk=1; ssk<ArgsStack.top().size(); ssk++) vv += ArgsStack.top()[ssk];
1354 return(true);
1355}
1356else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1357 if (ArgsStack.empty()) {
1358 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1359 << " ($" << vn << ")" << endl;
1360 vv = ""; return(false);
1361 }
1362 if ( (ka < 0) || (ka >= (int)ArgsStack.top().size()) ) {
1363 cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! "
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)
1370 CmdVarList::iterator it = variables.find(vn.substr(1));
1371 if (it == variables.end()) {
1372 cerr << " Commander::Var2Str/Error #vname Undefined variable "
1373 << vn << " ! " << endl;
1374 vv = ""; return(false);
1375 }
1376 sprintf(buff,"%d", (int)(*it).second.size());
1377 vv = buff; return(true);
1378}
1379else if (vn == "status") {
1380 sprintf(buff,"%d", _xstatus);
1381 vv = buff;
1382 return true;
1383}
1384else if ((vn == "retstr") || (vn == "retval")) {
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 {
1393 cerr << " Commander::Var2Str/Error Undefined variable "
1394 << vn << " ! " << endl;
1395 vv = ""; return false;
1396 }
1397}
1398
1399return false;
1400}
1401
1402/* --Methode-- */
1403bool Commander::SetVariable(string const & vn, string const & vv)
1404{
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);
1435 }
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 }
1447}
1448
1449/* --Methode-- */
1450bool Commander::GetVar(string const & vn, string & vv)
1451{
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) {
1459 for(unsigned int k=1; k<(*it).second.size(); k++) {
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;
1472 if ((idx < 0) || (idx > (int)(*it).second.size()-1))
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;
1494 return(false);
1495 }
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;
1506}
1507
1508/* --Methode-- */
1509bool Commander::SetVar(string const & vn, int idx, string const & val)
1510{
1511 if ( !CheckVarName(vn) ) {
1512 cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl;
1513 return(false);
1514 }
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 {
1533 if (idx >= (int)(*it).second.size())
1534 for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back("");
1535 (*it).second[idx] = val;
1536 fg = true;
1537 }
1538 return fg;
1539}
1540
1541/* --Methode-- */
1542bool Commander::SetVar(string const & vn, vector<string> const & val)
1543{
1544 if ( !CheckVarName(vn) ) {
1545 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1546 return(false);
1547 }
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;
1561}
1562
1563/* --Methode-- */
1564bool Commander::CheckVarName(string const & vn)
1565{
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 ---- "
1591 << endl;
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 }
1598 cout << "---------------------------------------------------------- "
1599 << endl;
1600}
1601
1602/* --Methode-- */
1603bool Commander::GetVarApp(string const & vn, string & vv)
1604{
1605 vv = "";
1606 // cout << " Commander::GetVarApp() Not available ! " << endl;
1607 return false;
1608}
1609
1610/* --Methode-- */
1611bool Commander::SetVarApp(string const & vn, string const & vv)
1612{
1613 // cout << " Commander::SetVarApp() Not available ! " << endl;
1614 return false;
1615}
1616
1617/* --Methode-- */
1618bool Commander::DeleteVarApp(string const & vn)
1619{
1620 // cout << " Commander::DeleteVarApp() Not available ! " << endl;
1621 return false;
1622}
1623
1624/* --Methode-- */
1625void Commander::ListVarApp()
1626{
1627 // cout << " Commander::ListVarApp() Not available ! " << endl;
1628 return;
1629}
1630
1631
1632/* --Methode-- */
1633bool Commander::GetVarEnv(string const & vn, string & vv)
1634{
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 }
1644}
1645
1646/* --Methode-- */
1647bool Commander::SetVarEnv(string const & vn, string const & vv)
1648{
1649 string pev = vn;
1650 pev += '=';
1651 pev += vv;
1652// if defined(Linux) || defined(AIX)
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 ?
1657// Idem AIX , Reza Dec 2005
1658// Pb apparu avec g++ 4 sur darwin (Mac) - Jan 2006
1659// Je fais copie pour tout le monde
1660 char* bev = new char[pev.size()+1];
1661 strcpy(bev, pev.c_str());
1662 if (putenv(bev) == 0) return true;
1663// else
1664// if (putenv(pev.c_str()) == 0) return true;
1665// endif
1666 else return false;
1667}
1668
1669/* --Methode-- */
1670bool Commander::DeleteVarEnv(string const & vn)
1671{
1672 // cout << " Commander::DeleteVarEnv() Not available ! " << endl;
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-- */
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-- */
1727void Commander::PushStack(vector<string>* pargs)
1728{
1729 // We push the argument list (args) on the stack if not NULL
1730 if (pargs != NULL) ArgsStack.push(*pargs);
1731 // We push also CommanderBloc and testresult on the stack
1732 CmdBlks.push(NULL);
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);
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();
1755 tresit_=TestsStack.top().tstresit;
1756 curtestresult_=TestsStack.top().tstcurres;
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 }
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}
1781
1782else if (kw == "set") {
1783 if (tokens.size() < 2) {
1784 cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl;
1785 return(1);
1786 }
1787
1788 if (tokens.size() == 2)
1789 SetVariable(tokens[0], tokens[1]);
1790 else {
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);
1801 }
1802 return 0;
1803}
1804else if (kw == "var2words") {
1805 if (tokens.size() < 2) {
1806 cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl;
1807 return(1);
1808 }
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}
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;
1824 return(1);
1825 }
1826 string xx = tokens[1];
1827 for (unsigned int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
1828 mAliases[tokens[0]] = xx;
1829}
1830
1831else if ( (kw == "unset") || (kw == "clearvar") ) {
1832 if (tokens.size() < 1) {
1833 cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;
1834 return(1);
1835 }
1836 else DeleteVar(tokens[0]);
1837}
1838// Evaluation d'expression en notation polonaise inverse
1839else if (kw == "rpneval") {
1840 try {
1841 RPNExpressionEvaluator rpn(tokens, 1);
1842 double res = rpn.Value();
1843 string vv = cval_dble2str(res);
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 }
1852}
1853else if (kw == "echo") {
1854 for (unsigned int ii=0; ii<tokens.size(); ii++)
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;
1861 return(1);
1862 }
1863 ofstream ofs(tokens[0].c_str(), ios::app);
1864 for (unsigned int ii=1; ii<tokens.size(); ii++)
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
1879else if (kw == "listvars" || kw == "listvar") ListVar();
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}
1922//---------------------------------------------
1923//--- Commandes de gestion des threads ------
1924//---------------------------------------------
1925else if (kw == "thrlist") {
1926 ListThreads();
1927 return(0);
1928}
1929else if ( (kw == "killthr") || (kw == "cancelthr") ) {
1930 if (tokens.size() < 1) {
1931 cout << "Commander::Interpret() Usage: killthr/cancelthr thrid" << endl;
1932 return(0);
1933 }
1934 uint_8 id = atol(tokens[0].c_str());
1935 bool fgkill = false;
1936 if (kw == "killthr") fgkill = true;
1937 StopThr(id, fgkill);
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
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") {
1964 AutoInitRand(1);
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;
1970 for (unsigned int ii=0; ii<tokens.size(); ii++)
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="";
1977 for(unsigned int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
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;
1993vector<bool> qottoks;
1994string kw, toks;
1995if (line.length() < 1) return(0);
1996LineToWords(line, kw, tokens, qottoks, toks, qw);
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 {
2007 if ((*it).second.cex) {
2008 // Doit-on l'executer sous forme de thread separe ?
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 }
2027 }
2028 else rc = (*it).second.cex->Execute(keyw, args, toks);
2029 }
2030 else cout << "Dont know how to execute " << keyw << " ? " << endl;
2031 }
2032 return(rc);
2033}
2034
2035/* --Methode-- */
2036int Commander::ExecFile(string& file, vector<string>& args)
2037{
2038char line_buff[1024];
2039FILE *fip;
2040int rcc = 0;
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;
2066while (fgets(line_buff,1023,fip) != NULL)
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);
2071 rcc = Interpret(line);
2072 if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
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-- */
2089void Commander::ListThreads()
2090{
2091 cout << "--- Commander::ListThreads()- command execution threads NThread="
2092 << CmdThrExeList.size() << " ---" << endl;
2093 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2094 tit != CmdThrExeList.end(); tit++) {
2095 cout << "Id=" << (*tit)->Id();
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;
2102 }
2103}
2104/* --Methode-- */
2105void Commander::StopThr(uint_8 id, bool fgkill)
2106{
2107 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2108 tit != CmdThrExeList.end(); tit++) {
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 }
2118 return;
2119 }
2120 }
2121 cout << "Commander::StopThr()/Error: No active thread with Id= " << id << endl;
2122}
2123
2124/* --Methode-- */
2125void Commander::CleanThrList()
2126{
2127 cout << "---- Commander::CleanThrList() Cleaning thrlist ----- \n";
2128 list<CommandExeThr *> thrcopie;
2129 int ncl = 0;
2130 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2131 tit != CmdThrExeList.end(); tit++) {
2132 if ( ((*tit)->IfEnded() || (*tit)->IfStopped()) && (ncl < 3) ) {
2133 cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
2134 delete (*tit);
2135 ncl++;
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-- */
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{
2225 for(unsigned int k=0; k<prl.length(); k++)
2226 if (! isalnum(prl[k]) ) prl[k] = 'Z';
2227}
2228
2229// Fonction qui remplace _ en \_
2230static string check_latex_underscore(string const & mot)
2231{
2232 string rs;
2233 for(unsigned int k=0; k<mot.length(); k++) {
2234 if (mot[k] == '_') rs += "\\_";
2235 else rs += mot[k];
2236 }
2237 return rs;
2238}
2239
2240/* --Methode-- */
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*/
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++) {
2312 gid = (*it).second.gid;
2313 if (gid == 0) continue;
2314 // fputs("\\begin{table}[h!] \n",fip);
2315 fputs("\\vspace{6mm} \n",fip);
2316 fputs("\\begin{center} \n ", fip);
2317 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
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++) {
2353 gid = (*it).second.gid;
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());
2358 if ((*it).second.desc.length() > 0)
2359 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
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);
2384cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
2385
2386return;
2387}
2388
2389
2390} // End of namespace SOPHYA
2391
Note: See TracBrowser for help on using the repository browser.